Goals

  1. Identify transcriptional patterns in AM associated with IAV, COVID-19, and common to both
  2. Determine source of IL6 and IL1B in the lung (if possible)

Setup

Load packages

library(ggplot2)
library(ggplotify)
library(ggsignif)
library(Cairo)
library(DESeq2)
library(pheatmap)
library(RColorBrewer)
library(viridis)
library(patchwork)
library(factoextra)
library(parallel)
library(uwot)
library(WGCNA)
library(ggsci)
library(topGO)
library(GO.db)
library(org.Hs.eg.db)
library(parallel)
library(doParallel)
library(biomaRt)
library(openxlsx)
registerDoParallel(makeCluster(12))
register(MulticoreParam(12))
options(gsubfn.engine = "R")
set.seed(12345)
source("~/utils/R/pretty_MA_plot.R")
source("~/utils/R/k_means_figure.R")
source("~/utils/R/plotPCA_manual.R")
fig2_pal = pal_npg("nrc")(9)

sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux Server 7.5 (Maipo)

Matrix products: default
BLAS:   /hpc/software/lapack/3.6.0_gcc/lib64/libblas.so.3.6.0
LAPACK: /hpc/software/lapack/3.6.0_gcc/lib64/liblapack.so.3.6.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
 [1] grid      parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] openxlsx_4.1.5              ggsignif_0.6.0              GenomicAlignments_1.22.1    Rsamtools_2.2.3            
 [5] Biostrings_2.54.0           XVector_0.26.0              pryr_0.1.4                  rasterize_0.1              
 [9] sp_1.4-2                    ggrastr_0.1.9               Cairo_1.5-12                ggplotify_0.0.5            
[13] RPushbullet_0.3.3           ggrepel_0.8.2               gtools_3.8.2                biomaRt_2.42.1             
[17] corrplot_0.84               ggforce_0.3.2               googledrive_1.0.1           googlesheets4_0.2.0        
[21] spgs_1.0-3                  readxl_1.3.1                rtracklayer_1.46.0          forcats_0.5.0              
[25] stringr_1.4.0               dplyr_1.0.0                 purrr_0.3.4                 readr_1.3.1                
[29] tidyr_1.1.0                 tibble_3.0.1                tidyverse_1.3.0             doParallel_1.0.15          
[33] iterators_1.0.12            foreach_1.5.0               org.Hs.eg.db_3.10.0         topGO_2.38.1               
[37] SparseM_1.78                GO.db_3.10.0                AnnotationDbi_1.48.0        graph_1.64.0               
[41] ggsci_2.9                   WGCNA_1.69                  fastcluster_1.1.25          dynamicTreeCut_1.63-1      
[45] uwot_0.1.8                  Matrix_1.2-18               factoextra_1.0.7            patchwork_1.0.1            
[49] viridis_0.5.1               viridisLite_0.3.0           RColorBrewer_1.1-2          pheatmap_1.0.12            
[53] DESeq2_1.26.0               SummarizedExperiment_1.16.1 DelayedArray_0.12.3         BiocParallel_1.20.1        
[57] matrixStats_0.56.0          Biobase_2.48.0              GenomicRanges_1.38.0        GenomeInfoDb_1.22.1        
[61] IRanges_2.20.2              S4Vectors_0.24.4            BiocGenerics_0.34.0         ggplot2_3.3.2              

loaded via a namespace (and not attached):
  [1] backports_1.1.8        Hmisc_4.4-0            BiocFileCache_1.10.2   splines_3.6.3          digest_0.6.25         
  [6] htmltools_0.5.0        fansi_0.4.1            magrittr_1.5           checkmate_2.0.0        memoise_1.1.0         
 [11] cluster_2.1.0          annotate_1.64.0        modelr_0.1.8           askpass_1.1            prettyunits_1.1.1     
 [16] jpeg_0.1-8.1           colorspace_1.4-1       rappdirs_0.3.1         blob_1.2.1             rvest_0.3.5           
 [21] haven_2.3.1            xfun_0.15              crayon_1.3.4           RCurl_1.98-1.2         jsonlite_1.7.0        
 [26] genefilter_1.68.0      impute_1.60.0          survival_3.1-8         glue_1.4.1             polyclip_1.10-0       
 [31] gtable_0.3.0           zlibbioc_1.32.0        scales_1.1.1           DBI_1.1.0              Rcpp_1.0.4.6          
 [36] progress_1.2.2         xtable_1.8-4           htmlTable_2.0.0        gridGraphics_0.5-0     foreign_0.8-75        
 [41] bit_1.1-15.2           preprocessCore_1.48.0  Formula_1.2-3          htmlwidgets_1.5.1      httr_1.4.1            
 [46] acepack_1.4.1          ellipsis_0.3.1         farver_2.0.3           pkgconfig_2.0.3        XML_3.99-0.3          
 [51] nnet_7.3-12            dbplyr_1.4.4           locfit_1.5-9.4         tidyselect_1.1.0       rlang_0.4.6           
 [56] munsell_0.5.0          cellranger_1.1.0       tools_3.6.3            cli_2.0.2              generics_0.0.2        
 [61] RSQLite_2.2.0          broom_0.5.6            knitr_1.29             bit64_0.9-7            fs_1.4.2              
 [66] zip_2.0.4              nlme_3.1-144           xml2_1.3.2             compiler_3.6.3         rstudioapi_0.11       
 [71] beeswarm_0.2.3         curl_4.3               png_0.1-7              reprex_0.3.0           tweenr_1.0.1          
 [76] geneplotter_1.64.0     stringi_1.4.6          lattice_0.20-38        vctrs_0.3.1            pillar_1.4.4          
 [81] lifecycle_0.2.0        BiocManager_1.30.10    data.table_1.12.8      bitops_1.0-6           R6_2.4.1              
 [86] latticeExtra_0.6-29    gridExtra_2.3          vipor_0.4.5            codetools_0.2-16       MASS_7.3-51.5         
 [91] assertthat_0.2.1       openssl_1.4.2          withr_2.2.0            GenomeInfoDbData_1.2.2 hms_0.5.3             
 [96] rpart_4.1-15           rvcheck_0.1.8          lubridate_1.7.9        base64enc_0.1-3        ggbeeswarm_0.6.0      

Import data

mp = readRDS("/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_script_bulk_des_no_hURNA.rds")
mp$covid_confirmed = factor(mp$covid_confirmed)
mp$sex = factor(mp$gender)

#set up for comparison by diagnosis
mp$Diagnosis = gsub("-| ", "_", as.character(mp$pna_type))
mp$Diagnosis = factor(mp$Diagnosis, 
                      levels = c("Healthy_Control", "Non_Pneumonia_Control", "COVID_19", 
                                 "Other_Viral_Pneumonia", "Other_Pneumonia"))
mp$neutrophilic = mp$percent_neutrophils > 50
#for modeling, etc
mp$finite_day_of_intubation = mp$day_of_intubation
mp$finite_day_of_intubation[is.infinite(mp$finite_day_of_intubation)] = NA
mp$day0_sample = factor(mp$day_of_intubation >= 0 & mp$day_of_intubation <=2)
mp$day0_sample[is.na(mp$day0_sample)] = FALSE
design(mp) = as.formula("~ Diagnosis")
metadata = as.data.frame(colData(mp))

Summary stats

Number of samples overall

table(mp$pna_type, useNA = "always")

      Healthy Control Non-Pneumonia Control              COVID-19 Other Viral Pneumonia       Other Pneumonia 
                    5                    24                    82                    29                   103 
                 <NA> 
                    0 

Number of patients

bulk_patients = colData(mp) %>% 
  as.data.frame() %>% 
  dplyr::select(study_id, covid_confirmed, pna_type) %>% 
  unique()
table(bulk_patients$covid_confirmed)

FALSE  TRUE 
  135    51 
table(bulk_patients$pna_type)

      Healthy Control Non-Pneumonia Control              COVID-19 Other Viral Pneumonia       Other Pneumonia 
                    5                    23                    51                    23                    84 

Number of serial samples

n_samples = table(metadata$patient_id)
serial_patients = names(n_samples[n_samples > 1])
length(serial_patients)
[1] 41

Distribution of days

ggplot(metadata, aes(x = day_of_intubation)) +
  geom_histogram(fill = "dodgerblue4")

PCA

Calculate and organize

mp_vst = vst(mp, nsub = 3000, fitType = "local") #know from later that local is best
mp_counts = counts(estimateSizeFactors(mp), normalized = T)
pca_data = plotPCA_manual(mp_vst,
                          intgroup = c("covid_confirmed"),
                          pcs = 10)
pca_data$data = left_join(pca_data$data,
                     as.data.frame(colData(mp)),
                     by = c("name" = "sample", "covid_confirmed"))

#merge counts and pca data
gene_conv = as.data.frame(rowData(mp)) %>% 
  rownames_to_column(var = "ensembl_gene_id")
merge_counts = mp_counts %>% 
  t() %>%
  as.data.frame() %>% 
  rownames_to_column(var = "name")

#merge together for featureplot dataset
fp_data = left_join(pca_data$data, merge_counts, by = "name")

How many PCs?

#scree plot   
fviz_eig(pca_data$pca, 
         barfill = "dodgerblue4", 
         xlab = "Principal Component",
         ylab = "Percent Variance Explained", 
         main = "",
         ncp = 50,
         ggtheme = theme_bw(),
         addlabels = T) #4-5 PCs will do it

Examine loadings

loadings = pca_data$pca$rotation %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "ensembl_gene_id") %>% 
  right_join(gene_conv, .)
Joining, by = "ensembl_gene_id"

PC1: MoAM Character

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = percent_total_CD206_high)) +
  geom_point(size = 3)

fabp4_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000170323))) +
  geom_point() +
  scale_color_viridis(name = "Log2(FABP4 Counts)")
spp1_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000118785))) +
  geom_point() +
  scale_color_viridis(name = "Log2(SPP1 Counts)")
fabp4_plot + spp1_plot

PC2: Patterns of activation (also by milieu)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = C_Reactive_Protein)) +
  geom_point(size = 3)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = LDH)) +
  geom_point(size = 3)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = FERRITIN)) +
  geom_point(size = 3)

inhba_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000122641))) +
  geom_point() +
  scale_color_viridis(name = "Log2(INHBA)")
il1b_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000125538))) +
  geom_point() +
  scale_color_viridis(name = "Log2(IL1b)")

After adding healthy controls this is longer true.

PC3: Male/female?

ggplot(fp_data, aes(x = PC2, y = PC3, color = gender)) +
  geom_point(size = 3)

xist_plot = ggplot(fp_data, aes(x = PC2, y = PC3, color = log2(ENSG00000229807))) +
  geom_point() +
  scale_color_viridis(name = "Log2(XIST)")

Not really

Condition

ggplot(fp_data, aes(x = PC1, y = PC2, color = Diagnosis)) +
  geom_point(size = 2) +
  stat_ellipse()

Day of intubation

ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(day_of_intubation))) +
  geom_point(size = 3)

No clear separation.

Determine best dispersion estimates

Parametric

#note: DESeq is refitting far too many genes. Need to turn this off.
mp_des_parametric = DESeq(mp, 
                          fitType = "parametric",
                          parallel = T,
                          minReplicatesForReplace = Inf)
estimating size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers
plotDispEsts(mp_des_parametric, cex = 0.1)

This fit really isn’t bad, but overestimates at lower expression (probably not a huge deal).

Local

mp_des_local = DESeq(mp,
                     fitType = "local",
                     parallel = T,
                     minReplicatesForReplace=Inf)
estimating size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers
plotDispEsts(mp_des_local, cex = 0.1)


mp_des = mp_des_local
rm(mp_des_local, mp_des_parametric)

Still not perfect, but a lot better.

#used a few times later; safest to put here
#identify infected samples
non_human_genes = subset(gene_conv, !(grepl("^ENSG", ensembl_gene_id))) #human genes all have this prefix
non_human_genes$gene_name[non_human_genes$ensembl_gene_id == "gene-UJ99_s6gp1"] = "NA" #neuraminidase was misread
non_human_genes$virus = factor(ifelse(grepl("UJ99", non_human_genes$ensembl_gene_id),
                               yes = "Influenza A/California/07/2009",
                               no = "SARS-CoV-2"))
cov2_genes = subset(non_human_genes, grepl("SARS|GU280", ensembl_gene_id))
iav_genes = subset(non_human_genes, grepl("UJ99", ensembl_gene_id))
flu_counts = counts(mp_des, normalized = T)[iav_genes$ensembl_gene_id, ]
flu_detected = colnames(flu_counts[, colSums(flu_counts) > 0])
cov2_counts = counts(mp_des, normalized = T)[cov2_genes$ensembl_gene_id, ]
cov2_detected = colnames(cov2_counts[, colSums(cov2_counts) > 0])
mp_des$sars_cov2_detected = factor(mp_des$sample %in% cov2_detected)
mp_des$iav_h1n1_detected = factor(mp_des$sample %in% flu_detected)

## Replicating CoV2 samples
### overall
antisense_counts = cov2_counts["SARS_CoV_2_antisense_genome", ]
sense_counts = cov2_counts[2:nrow(cov2_counts), ]
replicating_cov2 = intersect(names(antisense_counts)[antisense_counts > 0],
                             colnames(sense_counts[, colSums(sense_counts) > 0]))
### just covid
percent_detected_covid = length(unique(subset(metadata, sample %in% cov2_detected & covid_confirmed == TRUE)$study_id)) / length(unique(subset(metadata, covid_confirmed == TRUE)$study_id)) * 100
percent_detected_covid
[1] 66.66667
percent_replicating_covid = length(unique(subset(metadata, sample %in% replicating_cov2 & covid_confirmed == TRUE)$study_id)) / length(unique(subset(metadata, covid_confirmed == TRUE)$study_id)) * 100
percent_replicating_covid
[1] 25.4902
percent_replicating_covid / percent_detected_covid * 100
[1] 38.23529

Sanity checks

SARS-CoV-2

Does expression of viral genes correlate with covid diagnosis?

cov2_counts = lapply(cov2_genes$ensembl_gene_id, function(x){
  counts = plotCounts(mp,
                      gene = x,
                      intgroup = "Diagnosis",
                      returnData = T, 
                      pc = T)
  counts$gene = x
  return(counts)})
cov2_counts = bind_rows(cov2_counts)

ggplot(cov2_counts, aes(x = Diagnosis, y = count, fill = gene)) +
  geom_boxplot() +
  scale_y_log10()

Now that we have all of the necessary metadata, this looks fantastic.

Do counts cluster by virus and diagnosis?

viral_counts = counts(mp_des, normalized = T) 
viral_counts = viral_counts[non_human_genes$ensembl_gene_id, ]
viral_counts = log10(viral_counts + 0.5)

virus_detection = vector(mode = "character", length = ncol(mp_des))
for(i in 1:ncol(mp_des))
{
  has_covid = mp_des$covid_confirmed[i] == TRUE
  has_iav_h1n1 = mp_des$INFLUENZA_A_H1_2009[i] == "Positive"
  has_other_coronavirus = mp_des$any_coronavirus_non_covid[i] == TRUE
  #recode NA as FALSE for safety
  if(is.na(has_iav_h1n1)) 
  {
    has_iav_h1n1 = FALSE
  }
  if(is.na(has_other_coronavirus)) 
  {
    has_other_coronavirus = FALSE
  }
  
  if(has_covid == TRUE && has_iav_h1n1 == TRUE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "SARS-CoV-2 & Other Coronavirus & Influenza A/California/07/2009"
  } else if(has_covid == TRUE && has_iav_h1n1 == FALSE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "SARS-CoV-2"
  } else if(has_covid == FALSE && has_iav_h1n1 == TRUE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "Influenza A/California/07/2009"
  } else if(has_covid == FALSE && has_iav_h1n1 == FALSE && has_other_coronavirus == TRUE)
  {
     virus_detection[i] = "Other Coronavirus"
  } else if(has_covid == TRUE && has_iav_h1n1 == TRUE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "SARS-CoV-2 & Influenza A/California/07/2009"
  } else if(has_covid == TRUE && has_iav_h1n1 == FALSE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "SARS-CoV-2 & Other Coronavirus"
  } else if(has_covid == FALSE && has_iav_h1n1 == TRUE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "Other Coronavirus & Influenza A/California/07/2009"
  } else
  {
    virus_detection[i] = NA
  }
}
mp_des$detected_viruses = factor(virus_detection)
  
diagnosis_annotation = as.data.frame(colData(mp_des)) %>% 
  dplyr::select(Diagnosis = detected_viruses)
gene_annotation = non_human_genes %>% 
  remove_rownames() %>% 
  column_to_rownames("ensembl_gene_id") %>% 
  dplyr::select(`Viral Origin` = virus)
gene_names = non_human_genes$gene_name
gene_names[gene_names == "SARS_CoV_2_antisense_genome"] = "Antisense"

viral_expression_heatmap = pheatmap(viral_counts,
        clustering_method = "ward.D2",
        show_colnames = F,
        color = inferno(100),
        annotation_col = diagnosis_annotation,
        annotation_row = gene_annotation,
        labels_row = gene_names,
        annotation_colors = list(Diagnosis = c("SARS-CoV-2" = fig2_pal[1], "Other Coronavirus" = fig2_pal[2],
                                                "Influenza A/California/07/2009" = fig2_pal[3], "Other Coronavirus & Influenza A/California/07/2009" = fig2_pal[4]),
                                  `Viral Origin` = c("SARS-CoV-2" = fig2_pal[1], "Influenza A/California/07/2009" = fig2_pal[3])),
        angle_col = 45, 
        annotation_names_row = F, 
        fontsize = 24)

Patient 1174

This patient apparently met criteria for COVID well before the first known cases in Chicago

cov2_counts = counts(mp_des, normalized = T)[cov2_genes$ensembl_gene_id, ]
samples_1174 = mp_des$study_id == "1174"
samples_1174[is.na(samples_1174)] = FALSE
tubes_1174 = mp_des$sample[samples_1174]
cov2_counts_1174 = cov2_counts[, tubes_1174]
cov2_counts_1174
SARS_CoV_2_antisense_genome             gene-GU280_gp01             gene-GU280_gp02             gene-GU280_gp03 
                          0                           0                           0                           0 
            gene-GU280_gp04             gene-GU280_gp05             gene-GU280_gp06             gene-GU280_gp07 
                          0                           0                           0                           0 
            gene-GU280_gp08             gene-GU280_gp09             gene-GU280_gp10             gene-GU280_gp11 
                          0                           0                           0                           0 

No detection, at least in macrophages.

Do CoV2 reads decrease over time?

Checking for viral clearance

covid_cases = mp_des[, mp_des$covid_confirmed == TRUE]
covid_counts = counts(covid_cases, normalized = T)
covid_counts = covid_counts[cov2_genes$ensembl_gene_id, ]

covid_counts = covid_counts %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "gene") %>% 
  pivot_longer(cols = "340195046":"340239867",
               names_to = "sample",
               values_to = "Counts") %>% 
  left_join(., non_human_genes, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::select(-c(gene, virus)) %>% 
  left_join(., as.data.frame(colData(mp_des)), by = "sample")

ggplot(covid_counts, aes(x = day_of_intubation, y = Counts)) +
  facet_wrap(~ gene_name, scales = "free_y") +
  geom_point() +
  geom_smooth(se = F)

Unfortunately this is somewhat binarized. Better to treat it as such.

time_cor

    Spearman's rank correlation rho

data:  covid_counts_binarized$all_viral_counts and covid_counts_binarized$day_of_intubation
S = 35853, p-value = 0.0008307
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
-0.445437 

Export for modeling core

col_types = unlist(lapply(metadata, class))
list_cols = names(col_types[col_types == "AsIs"])
safe_metadata = metadata %>% 
  dplyr::select(-c(all_of(list_cols))) %>% 
  as.data.frame()
write.csv(safe_metadata, "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_metadata.csv")
write.csv(counts(mp_des, normalized = F), "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_counts_raw.csv")
write.csv(counts(mp_des, normalized = T), "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_counts_deseq2_normalized.csv")

Which samples are worth sequencing further?

First batch

good_samples = mp_des[, ((!is.na(mp_des$RIN) & mp_des$RIN >= 7) & 
                    mp_des$STAR_mqc_generalstats_star_uniquely_mapped_percent >= 30 &
                    mp_des$featureCounts_mqc_generalstats_featurecounts_percent_assigned >= 30) &
                    mp_des$RNA_concentration_pg_ul >= 125 |
                    (mp_des$iav_h1n1_detected == TRUE | mp_des$sars_cov2_detected == TRUE)]

selection_data = as.data.frame(colData(good_samples)) %>% 
  dplyr::select(sample, tc_pt_study_id, RIN, STAR_mqc_generalstats_star_uniquely_mapped_percent,
         featureCounts_mqc_generalstats_featurecounts_percent_assigned, iav_h1n1_detected, 
         sars_cov2_detected, covid_confirmed, batch, RNA_concentration_pg_ul, pna_type)
selection_data

Keepers:
- 340224808 (IAV) - 304017553 (IAV + likely another coronavirus) - 340239805 (Cov2) - 340233896 (Cov2) - 340239790 (Cov2) - 340239789 (Cov2) - 304012699 (Other – likely another coronavirus) - 300312389 (other) - 304020362 (other)

keepers = selection_data %>% 
  dplyr::filter(sample %in% c(304020298, 340224808, 304017553, 340239805, 340233896,
                              340239790, 340239789, 304012699, 300312389, 304020362)) %>% 
  mutate(vol_for_250_pg = round(250 / RNA_concentration_pg_ul, digits = 3))
keepers$dilution = ifelse(keepers$vol_for_250_pg > 0.5,
                          yes = 1,
                          no = ifelse(keepers$vol_for_250_pg > 0.1,
                                      yes = 5,
                                      no = 20))
keepers$dilution_vol_for_250_pg = round(250 / (keepers$RNA_concentration_pg_ul / keepers$dilution), digits = 3)
write.csv(keepers, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200612_resequencing_samples.csv")
keepers

Signatures associated with SARS-CoV-2

Single genes

IL6

il6_counts = plotCounts(mp_des, 
           gene = "ENSG00000136244",
           normalized = T,
           intgroup = "covid_confirmed",
           returnData = T) %>% 
  rownames_to_column(var = "sample") %>% 
  left_join(., 
            metadata,
            by = c("sample", "covid_confirmed"))

cor.test(il6_counts$count, il6_counts$percent_total_CD206_high)

    Pearson's product-moment correlation

data:  il6_counts$count and il6_counts$percent_total_CD206_high
t = -1.967, df = 214, p-value = 0.05047
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.2620931112  0.0002344531
sample estimates:
       cor 
-0.1332627 
il6_plot = ggplot(il6_counts, aes(x = percent_total_CD206_high, y = count, color = covid_confirmed)) +
  geom_point(size = 3) +
  scale_y_log10() +
  ylab("IL6 Counts")

Later confirmed NSD by group. Clearly correlates with MoAM character.

IL1b

il1b_counts = plotCounts(mp_des, 
           gene = "ENSG00000125538",
           normalized = T,
           intgroup = "covid_confirmed",
           returnData = T) %>% 
  rownames_to_column(var = "sample") %>% 
  left_join(., 
            metadata,
            by = c("sample", "covid_confirmed"))

cor.test(il1b_counts$count, il1b_counts$percent_total_CD206_high)

    Pearson's product-moment correlation

data:  il1b_counts$count and il1b_counts$percent_total_CD206_high
t = -3.8972, df = 214, p-value = 0.0001302
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3779331 -0.1283454
sample estimates:
       cor 
-0.2574278 
il1b_plot = ggplot(il1b_counts, aes(x = percent_total_CD206_high, y = count, color = covid_confirmed)) +
  geom_point(size = 3) +
  scale_y_log10() + 
  ylab("IL1b Counts")

il6_plot / il1b_plot

Later confirmed significantly downregulated, actually.

Basic DEA

Gene hits

Versus healthy controls

cov2_vs_hc_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Healthy_Control"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_hc_results_ids = cov2_vs_hc_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_hc_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_healthycontrols.csv")

cov2_vs_hc_results_ids

Upregulation of CoV-2 genes is gorgeous

Versus non-pna (sick) controls

cov2_vs_npc_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Non_Pneumonia_Control"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_npc_results_ids = cov2_vs_npc_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_npc_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_nonpneumoniacontrols.csv")

cov2_vs_npc_results_ids

Versus other viral PNA

cov2_vs_ovp_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Viral_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_ovp_results_ids = cov2_vs_ovp_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
cov2_vs_ovp_results_ids

write.csv(cov2_vs_ovp_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_otherviralpneumonia.csv")

Versus other PNA

cov2_vs_other_pna_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_other_pna_results_ids = cov2_vs_other_pna_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_other_pna_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_otherpneumonia.csv")

cov2_vs_other_pna_results_ids

MA Plot

pretty_MA_plot(cov2_vs_ovp_results, custom_annotation =  gene_conv)

Heatmap

How many clusters does it take?

elbow = k_elbow(dge = mp_des, design = "~Diagnosis", 
        cores = 12, 
        minReps = Inf,
        random_seed = 12345,
        max_k = 25,
        qval_cutoff = 0.01)
elbow

5 seems fair.

intubation_pal = colorRampPalette(brewer.pal(n = 9, name = "Purples")[3:9])(max(mp_des$finite_day_of_intubation, na.rm = T) + 1)
intubation_pal[1:3] = rep("#000000",3) #highlight "D0"

cov2_kmeans_noclustering = k_means_figure(dge = mp_des,
                                 design = "~Diagnosis",
                                 k = 5,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("Diagnosis", "finite_day_of_intubation"),
                                 breaks = seq(-2, 2, length.out=101),
                                 cores = 12,
                             minReps = Inf,
                             return_genes = T,
                             display_go_terms = F,
                             return_go_terms = F,
                             cluster_columns = F,
                             show_rownames = F,
                             baseMeanCutoff = 20,
                             random_seed = 12345,
                             qval_cutoff = 0.05,
                             annotation_colors = list(Diagnosis = c("Healthy_Control" = fig2_pal[6],
                                                                    "Non_Pneumonia_Control" = fig2_pal[2],
                                                                    "COVID_19" = fig2_pal[1], 
                                                                    "Other_Viral_Pneumonia" = fig2_pal[3],
                                                                    "Other_Pneumonia" = fig2_pal[4]),
                                                      finite_day_of_intubation =  intubation_pal), 
                             custom_order = c(3, 5, 1, 2, 4), 
                             sortColumns = T,
                             column_sort_factors = c("Diagnosis", "finite_day_of_intubation"))

cov2_kmeans_clustered = k_means_figure(dge = mp_des,
                                 design = "~Diagnosis",
                                 k = 5,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("Diagnosis", "finite_day_of_intubation"),
                                 breaks = seq(-2, 2, length.out=101),
                                 cores = 12,
                             minReps = Inf,
                             return_genes = T,
                             display_go_terms = F,
                             return_go_terms = T,
                             cluster_columns = T,
                             show_rownames = F,
                             baseMeanCutoff = 20,
                             random_seed = 12345,
                             qval_cutoff = 0.05,
                             annotation_colors = list(Diagnosis = c("Healthy_Control" = fig2_pal[6],
                                                                    "Non_Pneumonia_Control" = fig2_pal[2],
                                                                    "COVID_19" = fig2_pal[1], 
                                                                    "Other_Viral_Pneumonia" = fig2_pal[3],
                                                                    "Other_Pneumonia" = fig2_pal[4]),
                                                      finite_day_of_intubation =  intubation_pal), 
                             custom_order = c(3, 5, 1, 2, 4))
for(i in 1:length(cov2_kmeans_clustered$GO))
{
  cov2_kmeans_clustered$GO[[i]]$cluster = i
}
cov2_kmeans_clustered$go_df = bind_rows(cov2_kmeans_clustered$GO) %>% 
  arrange(cluster, padj)
cov2_kmeans_clustered$expression = counts(mp_des, normalized = T) %>% 
  as.data.frame() %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  dplyr::filter(ensembl_gene_id %in% cov2_kmeans_clustered$genes$gene) %>% 
  right_join(gene_conv, .)
saveRDS(cov2_kmeans_clustered, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200802_k_means_clustered.rds")
saveRDS(cov2_kmeans_noclustering, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_k_means_unclustered.rds")
write.csv(cov2_kmeans_clustered$genes, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_k_means_genes.csv")
write.csv(cov2_kmeans_clustered$go_df, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_k_means_GO.csv")

This is actually very cool (and nicely foreshadows the later WGCNA results). C1: mostly COVID-related(!); highly enriched for type I interferon response (not production so much), as well as MHC-I. C2: mostly nonviral pneumonias. Pretty classic STAT3 inflammatory response.

D0 Heatmap

d0_des = mp_des[, !is.na(mp_des$day_of_intubation) & mp_des$day_of_intubation <= 2 & mp_des$day_of_intubation >= 0]
# cov2_d0_kmeans_noclustering = k_means_figure(dge = d0_des, 
#                                  design = "~Diagnosis",
#                                  k = 3,
#                                  go_annotations = "org.Hs.eg.db",
#                                  ensembl_db = "hsapiens_gene_ensembl",
#                                  legend_factors = c("Diagnosis", "percent_total_CD206_high"),
#                                  breaks = seq(-3, 3, length.out=101),
#                                  cores = 12,
#                              minReps = Inf,
#                              return_genes = T,
#                              display_go_terms = F,
#                              return_go_terms = T,
#                              cluster_columns = F,
#                              label_fontsize = 2,
#                              customAnno = gene_conv,
#                              annoJoinCol = "ensembl_gene_id",
#                              sortColumns = T,
#                              colSortFactor = "Diagnosis",
#                              baseMeanCutoff = 20)

cov2_d0_kmeans_clustered = k_means_figure(dge = d0_des, 
                                 design = "~Diagnosis",
                                 k = 3,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("Diagnosis", "percent_total_CD206_high"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12,
                             minReps = Inf,
                             return_genes = T,
                             display_go_terms = F,
                             return_go_terms = T,
                             cluster_columns = T,
                             label_fontsize = 2,
                             customAnno = gene_conv,
                             annoJoinCol = "ensembl_gene_id",
                             baseMeanCutoff = 20)

Individual genes

CCL24

This was an interesting COVID-specific hit. According to published data, it is a highly selective chemoattractant for T cells. Would expect that it should correlate with T cell abundance.

ccl24_counts = plotCounts(mp_des, 
                          gene = "ENSG00000106178",
                          intgroup = "Diagnosis",
                       normalized = T,
                       pc = T,
                       returnData = T)
ggplot(ccl24_counts, aes(x = Diagnosis, y = count, fill  = Diagnosis)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) +
  geom_jitter(size = 0.1, width = 0.25) +
  scale_y_continuous(trans = "log10") +
  scale_fill_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non_Pneumonia_Control" = fig2_pal[2],
                               "COVID_19" = fig2_pal[1],
                               "Other_Viral_Pneumonia" = fig2_pal[3],
                               "Other_Pneumonia" = fig2_pal[4])) +
  scale_x_discrete(labels = c("Healthy_Control" = "Healthy\nControl",
                               "Non_Pneumonia_Control" = "Non-Pneumonia\nControl",
                               "COVID_19" = "COVID-19",
                               "Other_Viral_Pneumonia" = "Other Viral\nPneumonia",
                               "Other_Pneumonia" = "Other\nPneumonia")) +
  xlab("") +
  ylab("CCL24 Counts") +
  theme_bw() +
  theme(legend.position = "none", 
        text = element_text(size = 32, family = "Arial"),
        plot.title = element_text(hjust = 0.5))

ccl24_cd4 = plotCounts(mp_des, 
                          gene = "ENSG00000106178",
                          intgroup = "percent_CD4_total",
                       normalized = T,
                       returnData = T) %>% 
  rownames_to_column("sample")
ccl24_cd8 = plotCounts(mp_des, 
                          gene = "ENSG00000106178",
                          intgroup = "percent_CD8_total",
                       normalized = T,
                       returnData = T) %>% 
  rownames_to_column("sample")
ccl24_tcells = left_join(ccl24_cd4, ccl24_cd8) %>% 
  pivot_longer(names_to = "flow_parameter", 
               values_to = "percent",
               cols = c(percent_CD8_total, percent_CD4_total))
Joining, by = c("sample", "count")
ggplot(ccl24_tcells, aes(x = count, y = percent)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_wrap(~flow_parameter) +
  scale_x_log10()

Pretty poor correlation

IL-6

il6_counts = plotCounts(mp_des, 
                          gene = "ENSG00000136244",
                          intgroup = "Diagnosis",
                       normalized = T,
                       pc = T,
                       returnData = T)
ggplot(il6_counts, aes(x = Diagnosis, y = count, fill  = Diagnosis)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) +
  geom_jitter(size = 0.1, width = 0.25) +
  scale_y_continuous(trans = "log10") +
  scale_fill_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non_Pneumonia_Control" = fig2_pal[2],
                               "COVID_19" = fig2_pal[1],
                               "Other_Viral_Pneumonia" = fig2_pal[3],
                               "Other_Pneumonia" = fig2_pal[4])) +
  scale_x_discrete(labels = c("Healthy_Control" = "Healthy\nControl",
                               "Non_Pneumonia_Control" = "Non-Pneumonia\nControl",
                               "COVID_19" = "COVID-19",
                               "Other_Viral_Pneumonia" = "Other Viral\nPneumonia",
                               "Other_Pneumonia" = "Other\nPneumonia")) +
  xlab("") +
  ylab("IL-6 Counts") +
  theme_bw() +
  theme(legend.position = "none", 
        text = element_text(size = 32, family = "Arial"),
        plot.title = element_text(hjust = 0.5))

Sasha’s picks

All to start

sasha_genes = c("CCL20", "CCL24", "CCL3", "CCL8", "CCR2", "CCL2", "IL1A", "IL1B", "AREG", 
                "CXCR4", "TNFSF14", "CXCL3", "CXCL5", "CXCL1", "CXCL8", "ATF4", "CD164", 
                "MFGE8", "IL13RA1", "IL1RL1", "IL18R1", "VSIG4", "VEGFA", "DDIT4", "BAG3", 
                "DNAJB1", "HSP90AA6P", "HSPA1B", "HSPA1A")
sasha_genes = subset(gene_conv, gene_name %in% sasha_genes)

sasha_counts = mclapply(sasha_genes$ensembl_gene_id, function(x){
  counts = plotCounts(mp_des,
                      gene = x,
                      intgroup = "Diagnosis",
                      returnData = T,
                      normalized = T,
                      pc = T)
  counts$gene = x
  return(counts)})
sasha_counts = bind_rows(sasha_counts) %>% 
  left_join(., sasha_genes, by = c("gene" = "ensembl_gene_id"))

sasha_gene_plot = ggplot(sasha_counts, aes(x = Diagnosis, y = count, fill = Diagnosis)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) +
  geom_jitter(size = 0.1, width = 0.25) +
  scale_y_continuous(trans = "log10") +
  scale_fill_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non_Pneumonia_Control" = fig2_pal[2],
                               "COVID_19" = fig2_pal[1],
                               "Other_Viral_Pneumonia" = fig2_pal[3],
                               "Other_Pneumonia" = fig2_pal[4])) +
  scale_x_discrete(labels = c("Healthy_Control" = "Healthy\nControl",
                               "Non_Pneumonia_Control" = "Non-Pneumonia\nControl",
                               "COVID_19" = "COVID-19",
                               "Other_Viral_Pneumonia" = "Other Viral\nPneumonia",
                               "Other_Pneumonia" = "Other\nPneumonia")) +
  xlab("") +
  ylab("Gene Counts") +
  theme_bw() +
  theme(legend.position = "none") +
  facet_wrap(~gene_name)
sasha_gene_plot

Clustering

All samples

detection_rate = function(x)
{
  return(sum(x > 0) / length(x)) 
}

all_counts = counts(mp_des, normalized = T)
#get 500 most variable genes with > 10% detection
rv = rowVars(all_counts)
prop_detected = apply(X = all_counts, MARGIN = 1, FUN = detection_rate)
selection_criteria = data.frame(sample = rownames(all_counts), var = rv, prop_detected = prop_detected) %>% 
  filter(prop_detected >= 0.1 & var > 0) %>% 
  arrange(desc(var))
top_genes = as.character(selection_criteria$sample[1:1000])
top_all_counts = all_counts[top_genes, ]

annotation = colData(mp_des) %>% 
  as.data.frame() %>% 
  dplyr::select(covid_confirmed, 
                sars_cov2_detected,
                sex,
                #day_of_intubation,
                infection_type,
                percent_neutrophils,
                percent_total_CD206_high)
gene_annotation = gene_conv %>% 
  dplyr::filter(ensembl_gene_id %in% rownames(top_all_counts)) %>% 
  column_to_rownames(var = "ensembl_gene_id")

pheatmap(top_all_counts,
         cluster_rows = T,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_col = annotation,
         labels_row = gene_annotation$gene_name,
         scale = "row",
         show_rownames = T,
         fontsize_row = 2,
         show_colnames = F,
         breaks = seq(-3, 3, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(100),
         angle_col = 45)

Day 0

day0_samples = which(mp$day_of_intubation <= 2)
day0 = mp_des[, day0_samples]
day0_counts = counts(day0, normalized = T)

#get 1000 most variable genes
rv = rowVars(day0_counts)
prop_detected = apply(X = day0_counts, MARGIN = 1, FUN = detection_rate)
selection_criteria = data.frame(sample = rownames(day0_counts), var = rv, prop_detected = prop_detected) %>% 
  filter(prop_detected >= 0.1 & var > 0) %>% 
  arrange(desc(var))
top_genes = as.character(selection_criteria$sample[1:1000])
top_day0_counts = day0_counts[top_genes, ]

annotation = colData(day0) %>% 
  as.data.frame() %>% 
  dplyr::select(covid_confirmed, 
                sars_cov2_detected,
                gender,
                infection_type,
                percent_neutrophils,
                percent_total_CD206_high)
gene_annotation = gene_conv %>% 
  dplyr::filter(ensembl_gene_id %in% rownames(top_day0_counts)) %>% 
  column_to_rownames(var = "ensembl_gene_id")

pheatmap(top_day0_counts,
         cluster_rows = T,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_col = annotation,
         labels_row = gene_annotation$gene_name,
         scale = "row",
         show_rownames = T,
         show_colnames = F,
         fontsize_row = 2,
         breaks = seq(-3, 3, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(100),
         angle_col = 45)

Comparing different pathogens

Individual pathogens

pathogen_set = mp_des[, !is.na(mp$pathogen)]
pathogen_set$pathogen = factor(as.character(pathogen_set$pathogen)) #refactor
pathogen_kmeans = k_means_figure(dge = pathogen_set, 
                                 design = "~pathogen",
                                 k = 6,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("pathogen", "covid_confirmed"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12)

Probably too granular

Broad groupings

infection_type_kmeans = k_means_figure(dge = pathogen_set, 
                                 design = "~infection_type",
                                 k = 4,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("pathogen", "infection_type"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12)

Random

ACE2 counts

ace2_counts = plotCounts(mp_des, 
                         gene = "ENSG00000130234", 
                         intgroup = "covid_confirmed",
                         returnData = T,
                         normalized = T, 
                         pc = F)
ggplot(ace2_counts, aes(x = count)) +
  geom_histogram(fill = "dodgerblue4", ) +
  ylab("Number of Samples") +
  xlab("ACE2 Count")

Trajectories?

All samples

We will use PCA as is recommended to make computation feasible.

#select genes with > 10% detection, mean counts > 5
all_counts = t(counts(mp_des, normalized = T)) #need size normalization
prop_detected = apply(X = all_counts, MARGIN = 2, FUN = detection_rate)
all_counts = all_counts[, prop_detected > 0.1]
mean_detection = colMeans(all_counts)
all_counts = all_counts[, mean_detection >= 5]

all_pca = prcomp(all_counts)
fviz_eig(all_pca, 
         barfill = "dodgerblue4", 
         xlab = "Principal Component",
         ylab = "Percent Variance Explained", 
         main = "",
         ncp = 50,
         ggtheme = theme_bw(),
         addlabels = T) #20 should capture almost everything


total_umap = umap(X = all_counts, 
                  pca = 20, 
                  pca_center = T, 
                  n_threads = 1, 
                  scale = "Z", 
                  min_dist = 0.2)
rownames(total_umap) = rownames(all_counts)
colnames(total_umap) = c("UMAP_1", "UMAP_2")
total_umap = as.data.frame(total_umap)
total_umap$sample = rownames(total_umap)
total_umap = left_join(total_umap, metadata, by = "sample") %>% 
  arrange(study_id, day_of_intubation) # so we can draw paths

ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, color = Diagnosis)) +
  geom_point() +
  stat_ellipse()


ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, shape = study_id, color = day_of_intubation)) +
  geom_path(arrow = grid::arrow()) +
  scale_color_viridis() +
  facet_wrap(~ Diagnosis)

Patients actually separate out really well here. This might be worth including as a supplement. With that said, probably better to just use COVID patients for “trajectories”. It looks like there may be some structure to the COVID data.

Only COVID

#remove non-detected genes
#note that PCA should only use genes detected in all samples (3081)
COVID_counts = t(counts(mp_des[, mp_des$Diagnosis == "COVID_19"], normalized = T)) #need size normalization
prop_detected = apply(X = COVID_counts, MARGIN = 2, FUN = detection_rate)
COVID_counts = COVID_counts[, prop_detected > 0.1]
mean_detection = colMeans(COVID_counts)
COVID_counts = COVID_counts[, mean_detection >= 5]

COVID_pca = prcomp(COVID_counts)
fviz_eig(COVID_pca, 
         barfill = "dodgerblue4", 
         xlab = "Principal Component",
         ylab = "Percent Variance Explained", 
         main = "",
         ncp = 50,
         ggtheme = theme_bw(),
         addlabels = T) #20 should capture almost everything


COVID_umap = umap(X = COVID_counts, 
                  pca = 20, 
                  pca_center = T, 
                  n_threads = 1, 
                  scale = "Z", 
                  min_dist = 0.4)
rownames(COVID_umap) = rownames(COVID_counts)
colnames(COVID_umap) = c("UMAP_1", "UMAP_2")
COVID_umap = as.data.frame(COVID_umap)
COVID_umap$sample = rownames(COVID_umap)
COVID_umap = left_join(COVID_umap, metadata, by = "sample") %>% 
  arrange(study_id, day_of_intubation) # so we can draw paths

ggplot(COVID_umap, aes(x = UMAP_1, y = UMAP_2, color = day_of_intubation)) +
  scale_color_viridis() +
  geom_point()

ggplot(COVID_umap, aes(x = UMAP_1, y = UMAP_2, shape = study_id, color = day_of_intubation)) +
  scale_color_viridis() +
  geom_path(arrow = grid::arrow())

Not so much structure it seems.

WGCNA

What gene modules are associated with covid? Which change substantially over time on ventilator?
## Thesholding

#setup
enableWGCNAThreads(nThreads = 12)
Allowing parallel execution with up to 12 working processes.
WGCNAnThreads()
[1] 12
# Choose a set of soft-thresholding powers
powers = c(1:20)

# Call the network topology analysis functions
sft = pickSoftThreshold(all_counts, powerVector = powers, verbose = 5, networkType = "signed")
pickSoftThreshold: will use block size 3395.
 pickSoftThreshold: calculating connectivity for given powers...
   ..working on genes 1 through 3395 of 13176
   ..working on genes 3396 through 6790 of 13176
   ..working on genes 6791 through 10185 of 13176
   ..working on genes 10186 through 13176 of 13176
# Plot the results:
sizeGrWindow(9, 5)
par(mfrow = c(1,2))
cex1 = 0.9

# Scale-free topology fit index as a function of the soft-thresholding power
plot(sft$fitIndices[,1], 
     -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     xlab="Soft Threshold (power)",
     ylab="Scale Free Topology Model Fit,signed R^2",
     type="n",
     main = paste("Scale independence"))
text(sft$fitIndices[,1], 
     -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     labels=powers,
     cex=cex1,
     col="red")

# this line corresponds to using an R^2 cut-off of h
abline(h=0.90,col="red")

# Mean connectivity as a function of the soft-thresholding power
plot(sft$fitIndices[,1], 
     sft$fitIndices[,5],
     xlab="Soft Threshold (power)",
     ylab="Mean Connectivity", 
     type="n",
     main = paste("Mean connectivity"))
text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, cex=cex1,col="red")

7 looks like the intersection after adding healthy controls

Co-expression by similarity and adjacency

softPower = 7
adjacency = adjacency(all_counts, power = softPower, type = "signed")

Topological overlap matrix

# Turn adjacency into topological overlap
TOM = TOMsimilarity(adjacency, TOMType = "signed")
..connectivity..
..matrix multiplication (system BLAS)..
..normalization..
..done.

Cluster by TOM distance

geneTree = hclust(as.dist(dissTOM), method = "average")

Create modules

minModuleSize = 30 # may need to adjust

# Make modules based on clusters
dynamicMods = cutreeDynamic(dendro = geneTree, 
                            distM = dissTOM,
                            deepSplit = 2,
                            pamRespectsDendro = FALSE,
                            minClusterSize = minModuleSize)
 ..cutHeight not given, setting it to 0.989  ===>  99% of the (truncated) height range in dendro.
 ..done.
table(dynamicMods)
dynamicMods
   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
2734 2473 2350 1019  830  711  697  647  370  293  273  271  246  143  119 

Label modules (yeah this is dumb – rename later)

# Convert numeric labels into colors
dynamicColors = labels2colors(dynamicMods)
table(dynamicColors)
dynamicColors
       black         blue        brown         cyan        green  greenyellow      magenta midnightblue         pink 
         697         2473         2350          143          830          273          370          119          647 
      purple          red       salmon          tan    turquoise       yellow 
         293          711          246          271         2734         1019 
# Plot the dendrogram and colors underneath
sizeGrWindow(8,6)
plotDendroAndColors(geneTree, 
                    dynamicColors, 
                    "Dynamic Tree Cut",
                    dendroLabels = FALSE,
                    hang = 0.03,
                    addGuide = TRUE,
                    guideHang = 0.05,
                    main = "Gene dendrogram and module colors")

Looks like we captured the structure pretty well.

Merge similar modules

# Calculate eigengenes
MEList = moduleEigengenes(all_counts, 
                          colors = dynamicColors)
MEs = MEList$eigengenes

# Calculate dissimilarity of module eigengenes
MEDiss = 1-cor(MEs)

# Cluster module eigengenes
METree = hclust(as.dist(MEDiss), 
                method = "average")

# Plot the result
sizeGrWindow(7, 6)
plot(METree, 
     main = "Clustering of module eigengenes",
     xlab = "",
     sub = "")

#Now cut at height of 0.5 to get correlation of 0.5  
#standard is 0.25, but we have some really similar modules that are not relevant
MEDissThres = 0.25

# Plot the cut line into the dendrogram
abline(h=MEDissThres, 
       col = "red")

# Call an automatic merging function
merge = mergeCloseModules(all_counts, 
                          dynamicColors, 
                          cutHeight = MEDissThres, 
                          verbose = 3)
 mergeCloseModules: Merging modules whose distance is less than 0.25
   multiSetMEs: Calculating module MEs.
     Working on set 1 ...
     moduleEigengenes: Calculating 15 module eigengenes in given set.
   Calculating new MEs...
   multiSetMEs: Calculating module MEs.
     Working on set 1 ...
     moduleEigengenes: Calculating 15 module eigengenes in given set.
# The merged module colors
mergedColors = merge$colors

# Eigengenes of the new merged modules:
mergedMEs = merge$newMEs

# Rename to moduleColors
moduleColors = mergedColors

# Construct numerical labels corresponding to the colors
colorOrder = c("grey", standardColors(50))
moduleLabels = match(moduleColors, colorOrder)-1
MEs = mergedMEs

#replot
sizeGrWindow(12, 9)
plotDendroAndColors(geneTree, 
                    cbind(dynamicColors, mergedColors),
                    c("Dynamic Tree Cut", "Merged dynamic"),
                    dendroLabels = FALSE, 
                    hang = 0.03,
                    addGuide = TRUE, 
                    guideHang = 0.05)

No change

Relate back to traits

Without vent settings

# Define numbers of genes and samples
nGenes = ncol(all_counts)
nSamples = nrow(all_counts)
metadata = as.data.frame(colData(mp_des))
md_of_interest = metadata %>% 
  mutate(deceased = ifelse(binned_outcome == "Deceased",
                           yes = 1,
                           no = 0)) %>% 
  mutate(has_covid = ifelse(covid_confirmed == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(cov2_detected = ifelse(sars_cov2_detected == TRUE,
                                yes = 1,
                                no = 0)) %>% 
  mutate(has_pneumonia = ifelse(pna_type == "Non-Pneumonia Control",
                           yes = 0,
                           no = 1)) %>% 
  mutate(coinfection_detected = ifelse(any_nonviral == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(other_viral_pna = ifelse(pna_type == "Other Viral Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(nonviral_pna = ifelse(pna_type == "Other Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(is_healthy_control = ifelse(pna_type == "Healthy Control",
                           yes = 1,
                           no = 0)) %>% 
  dplyr::select(deceased, has_covid, cov2_detected, has_pneumonia,
                other_viral_pna, nonviral_pna, is_healthy_control,
                percent_neutrophils, percent_total_CD206_high,
                percent_CD4_total, percent_CD8_total, finite_day_of_intubation,
                C_Reactive_Protein, D_DIMER, PROCALCITONIN, mean_aps)
# Recalculate MEs with color labels
MEs0 = moduleEigengenes(all_counts, moduleColors)$eigengenes
MEs = orderMEs(MEs0)
moduleTraitCor = bicor(MEs, 
                     md_of_interest, 
                     use = "pairwise.complete.obs",
                     maxPOutliers = 0.05)
bicor: zero MAD in variable 'y'. Pearson correlation was used for individual columns with zero (or missing) MAD.
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, 
                                     nSamples) %>% 
  as.numeric() %>% 
  p.adjust(., method = "fdr") %>% 
  matrix(ncol = ncol(moduleTraitCor))
colnames(moduleTraitPvalue) = colnames(moduleTraitCor)
rownames(moduleTraitPvalue) = rownames(moduleTraitCor)
moduleTraitCor_hm = t(moduleTraitCor)
#just make significant or not
pvals_hm = t(moduleTraitPvalue) %>% 
  as.matrix()
pvals_hm[pvals_hm < 0.05] = ""
pvals_hm[pvals_hm != ""] = "NS"

labs = c("Deceased", "COVID-19", "SARS-CoV-2 Detected", "Any Pneumonia", "Other Viral Pneumonia", "Other Pneumonia",
         "Healthy Control", "% Neutrophils", "% Macrophages CD206-high", "% CD4 T", "% CD8 T",
         "Day of Intubation", "CRP", "D-Dimer", "Procalcitonin", "Mean APS")
module_cor_heatmap = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315)

module_cor_heatmap = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315, 
                              fontsize = 32)

Module 12 (turquoise) looks like the key MoAM cluster, 4 (blue) is key TRAM, and module 14 (purple) is likely our IFN cluster.

With vent settings

# Define numbers of genes and samples
nGenes = ncol(all_counts)
nSamples = nrow(all_counts)

md_of_interest = metadata %>% 
  mutate(deceased = ifelse(binned_outcome == "Deceased",
                           yes = 1,
                           no = 0)) %>% 
  mutate(has_covid = ifelse(covid_confirmed == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(cov2_detected = ifelse(sars_cov2_detected == TRUE,
                                yes = 1,
                                no = 0)) %>% 
  mutate(has_pneumonia = ifelse(pna_type == "Non-Pneumonia Control",
                           yes = 0,
                           no = 1)) %>% 
  mutate(coinfection_detected = ifelse(any_nonviral == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(other_viral_pna = ifelse(pna_type == "Other Viral Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(nonviral_pna = ifelse(pna_type == "Other Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(is_healthy_control = ifelse(pna_type == "Healthy Control",
                           yes = 1,
                           no = 0)) %>% 
  dplyr::select(deceased, has_covid, cov2_detected, has_pneumonia,
                other_viral_pna, nonviral_pna, is_healthy_control,
                percent_neutrophils, percent_total_CD206_high,
                percent_CD4_total, percent_CD8_total, finite_day_of_intubation,
                C_Reactive_Protein, D_DIMER, PROCALCITONIN, mean_aps,
                Static_Compliance, PF_ratio)

# Recalculate MEs with color labels
MEs0 = moduleEigengenes(all_counts, moduleColors)$eigengenes
MEs = orderMEs(MEs0)
moduleTraitCor = bicor(MEs, 
                     md_of_interest, 
                     use = "pairwise.complete.obs",
                     maxPOutliers = 0.05)
bicor: zero MAD in variable 'y'. Pearson correlation was used for individual columns with zero (or missing) MAD.
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, 
                                     nSamples) %>% 
  as.numeric() %>% 
  p.adjust(., method = "fdr") %>% 
  matrix(ncol = ncol(moduleTraitCor))
colnames(moduleTraitPvalue) = colnames(moduleTraitCor)
rownames(moduleTraitPvalue) = rownames(moduleTraitCor)

moduleTraitCor_hm = t(moduleTraitCor)
#just make significant or not
pvals_hm = t(moduleTraitPvalue) %>% 
  as.matrix()
pvals_hm[pvals_hm < 0.05] = ""
pvals_hm[pvals_hm != ""] = "NS"


labs = c("Deceased", "COVID-19", "SARS-CoV-2 Detected", "Any Pneumonia", "Other Viral Pneumonia", "Other Pneumonia",
         "Healthy Control", "% Neutrophils", "% Macrophages CD206-high", "% CD4 T", "% CD8 T",
         "Day of Intubation", "CRP", "D-Dimer", "Procalcitonin", "Mean APS",
         "Static Compliance", "P/F Ratio")
module_cor_heatmap_vent_mini = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315)

module_cor_heatmap_vent = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315, 
                              fontsize = 24)

saveRDS(module_cor_heatmap_vent, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200803_WGCNA_cor_heatmap.rds")

Module 13 (salmon) may also be interesting. Correlates with COVID, CRP, lymphocytes, and vent params!

Sanity check: are the CD206 modules TRAM/MoAM markers?

module_assignments = data.frame(ensembl_gene_id = colnames(all_counts),
                                module = factor(mergedColors)) %>% 
  left_join(., gene_conv)
Joining, by = "ensembl_gene_id"
write.csv(module_assignments,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_WGCNA_module_assignments.csv")

cd206_correlated = subset(module_assignments, module == "blue")
cd206_anticorrelated = subset(module_assignments, module == "turquoise")
cd206_correlated
cd206_anticorrelated

Pretty ideal, yeah

COVID-associated

Purple contains all of the CoV-2 genes!

covid_correlated_cd206_uncorrelated = subset(module_assignments, module == "purple")
covid_correlated_cd206_uncorrelated
write.csv(covid_correlated_cd206_uncorrelated,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_purple_module_14_genes.csv")

Pretty classic interferon response. Look at the GO.

#from k_means_figure
complete_counts = counts(mp_des, normalized = T)
universe = rownames(complete_counts[rowSums(complete_counts) > 0, ])
fisherTest = new("classicCount", testStatistic = GOFisherTest, name = "Fisher test")

cluster_genes = covid_correlated_cd206_uncorrelated$ensembl_gene_id
selection = as.numeric(universe %in% cluster_genes)
names(selection) = universe
go_data = new("topGOdata", 
              ontology = "BP", 
              allGenes = selection,
              geneSel = function(x){
                return(x == 1)},
              annot = annFUN.org, 
              mapping = "org.Hs.eg.db", 
              ID = "ensembl")

Building most specific GOs .....
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 16096 GO terms and 38209 relations. )

Annotating nodes ...............
    ( 16536 genes annotated to the GO terms. )
  
#run Fisher test
test_results = getSigGroups(go_data, fisherTest)

             -- Classic Algorithm -- 

         the algorithm is scoring 3412 nontrivial nodes
         parameters: 
             test statistic: Fisher test
module14_score = as.data.frame(score(test_results))
colnames(module14_score) = "pval"
module14_score = rownames_to_column(module14_score, var = "go_id")
  
#adjust p-values and take significant
module14_score$padj = p.adjust(module14_score$pval, method = "fdr")
module14_score = subset(module14_score, padj < 0.05)
module14_score$description = NA
for(i in 1:nrow(module14_score))
{
  module14_score$description[i] = GOTERM[[module14_score$go_id[i]]]@Term
}

#add descriptions
module14_score$full_go = paste(module14_score$go_id, module14_score$description)
write.csv(module14_score,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_purple_module_14_GO.csv")
module14_score

Pretty much all Type I interferon related. Most of the paper is here.

Module 13

This module has IRF1 and the MHC-I genes

module13 = subset(module_assignments, module == "salmon")
module13
write.csv(module13,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_salmon_module_13_genes.csv")
#from k_means_figure
cluster_genes = module13$ensembl_gene_id
selection = as.numeric(universe %in% cluster_genes)
names(selection) = universe
go_data = new("topGOdata", 
              ontology = "BP", 
              allGenes = selection,
              geneSel = function(x){
                return(x == 1)},
              annot = annFUN.org, 
              mapping = "org.Hs.eg.db", 
              ID = "ensembl")

Building most specific GOs .....
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 16096 GO terms and 38209 relations. )

Annotating nodes ...............
    ( 16536 genes annotated to the GO terms. )
  
#run Fisher test
test_results = getSigGroups(go_data, fisherTest)

             -- Classic Algorithm -- 

         the algorithm is scoring 2785 nontrivial nodes
         parameters: 
             test statistic: Fisher test
module13_score = as.data.frame(score(test_results))
colnames(module13_score) = "pval"
module13_score = rownames_to_column(module13_score, var = "go_id")
  
#adjust p-values and take significant
module13_score$padj = p.adjust(module13_score$pval, method = "fdr")
module13_score = subset(module13_score, padj < 0.05)
# module13_score$description = NA
# for(i in 1:nrow(module13_score))
# {
#   module13_score$description[i] = GOTERM[[module13_score$go_id[i]]]@Term
# }
# 
# #add descriptions
# module13_score$full_go = paste(module13_score$go_id, module13_score$description)
# write.csv(module13_score,
#           "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_salmon_module_13_GO.csv")
# module13_score

No significant hits.

Plot interesting modules

Purple module (14) and diagnosis, outcome

CCL24

ccl24_counts = rownames_to_column(ccl24_counts, var = "sample")
ccl24_counts = ccl24_counts[, 1:2]
colnames(ccl24_counts)[2] = "CCL24"
total_umap = left_join(total_umap, ccl24_counts)
Joining, by = "sample"
ccl24_umap = ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = CCL24, color = pna_type, shape = binned_outcome)) +
  geom_point() +
  theme_bw() +
  theme(text = element_text(size = 16, family = "Arial"),
        legend.text = element_text(size = 16, family = "Arial"),
        legend.title = element_text(size = 16, family = "Arial")) +
  scale_color_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non-Pneumonia Control" = fig2_pal[2],
                               "COVID-19" = fig2_pal[1],
                               "Other Viral Pneumonia" = fig2_pal[3],
                               "Other Pneumonia" = fig2_pal[4]),
                    na.value = "black") +
  scale_shape_manual(name = "",
                    values = c("Deceased" = 13,
                               "Discharged" = 19,
                               "Inpatient Facility" = 18,
                               "Other" = 18),
                               na.value = 1) +
scale_size_continuous(name = "CCL24 Counts", trans = "log10", range = c(1, 10)) +
  xlab("UMAP 1") +
  ylab("UMAP 2")
ccl24_umap 

This is really cool! This isolates most the the IFN-non-responsive COVID patients. Maybe this drives heterogeneity in celltype composition in the lung?

tcell_umap = ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = percent_CD3_total, color = pna_type, shape = binned_outcome)) +
  geom_point() +
  theme_bw() +
  theme(text = element_text(size = 16, family = "Arial"),
        legend.text = element_text(size = 16, family = "Arial"),
        legend.title = element_text(size = 16, family = "Arial")) +
  scale_color_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non-Pneumonia Control" = fig2_pal[2],
                               "COVID-19" = fig2_pal[1],
                               "Other Viral Pneumonia" = fig2_pal[3],
                               "Other Pneumonia" = fig2_pal[4]),
                    na.value = "black") +
  scale_shape_manual(name = "",
                    values = c("Deceased" = 13,
                               "Discharged" = 19,
                               "Inpatient Facility" = 18,
                               "Other" = 18),
                               na.value = 1) +
scale_size_continuous(name = "Percent Lymphocytes", range = c(1, 10)) +
  xlab("UMAP 1") +
  ylab("UMAP 2")

tcell_umap 

Brown/turquoise modules and day of intubation in COVID patients

TRAM content

ggplot(total_umap, aes(x = day_of_intubation, y = AEblue)) +
  geom_point() +
  geom_smooth()


ggplot(total_umap, aes(x = day_of_intubation, y = AEturquoise)) +
  geom_point() +
  geom_smooth()

Not much of a correlation…maybe a flat line, as I guess would be expected with near-constant recruitment.

Effect of ORF8 expression

Isolate counts

orf8 = cov2_genes$ensembl_gene_id[which(cov2_genes$gene_name == "ORF8")]
orf8_counts = plotCounts(mp_des, 
                         gene = orf8, 
                         intgroup = "pna_type",
                         returnData = T,
                         normalized = T, 
                         pc = T)
orf8_samples = rownames(subset(orf8_counts, count >0))

ggplot(orf8_counts, aes(x = pna_type, y = count)) +
  geom_boxplot() +
  geom_jitter(aes(color = count > 0)) +
  scale_y_log10() +
  ylab("ORF8 Counts") +
  xlab("") 

Not a ton of detection but very clean.

Association with interferon responses

mp_des$orf8_detected = mp_des$sample %in% orf8_samples
total_umap$orf8_detected = total_umap$sample %in% orf8_samples
ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = AEpurple, color = Diagnosis, shape = orf8_detected)) +
  geom_point()

Pretty clear spatial correlation…but in the opposite direction?

ggplot(total_umap, aes(x = orf8_detected, y = AEpurple)) +
  geom_boxplot() +
  geom_jitter(aes(color = Diagnosis))


high_cov2 = colnames(cov2_counts)[colSums(cov2_counts) > 50]
total_umap$cov2_detected = total_umap$sample %in% high_cov2
ggplot(total_umap, aes(x = cov2_detected, y = AEpurple)) +
  geom_boxplot() +
  geom_jitter(aes(color = Diagnosis))

This really just correlates with overall viral load (which correlates, in turn, with ORF8 levels). No support really for the ORF8 inhibition of the IFN response, at least at this stage.

Interferon response over time

WGCNA Module purple

Average expression

GO Categories

Pull from biomart

human_mart = useEnsembl("ensembl", dataset = "hsapiens_gene_ensembl", GRCh = 37)

#now pull down genes based on gene ontology (GO) definitions
typeI_IFN_response = getBM(attributes = c("ensembl_gene_id", "external_gene_name"),
                           filters = "go",
                           values = "GO:0060337",
                           mart = human_mart)
`select_()` is deprecated as of dplyr 0.7.0.
Please use `select()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.`filter_()` is deprecated as of dplyr 0.7.0.
Please use `filter()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.Cache found
IFNg_response = getBM(attributes = c("ensembl_gene_id", "external_gene_name"),
                           filters = "go",
                           values = "GO:0060333",
                           mart = human_mart)
Cache found

Assign mean expression

covid_umap = covid_umap %>% 
  left_join(., type1_counts) %>% 
  left_join(., type2_counts) %>% 
  left_join(., ifn_counts)
Joining, by = "sample"
Joining, by = "sample"
Joining, by = "sample"

Correlations

typei_cor = cor.test(covid_umap$typeI_IFN_response, covid_umap$finite_day_of_intubation)
typeii_cor = cor.test(covid_umap$IFNg_response, covid_umap$finite_day_of_intubation)
general_cor = cor.test(covid_umap$general_IFN_response, covid_umap$finite_day_of_intubation)

Plot

Second batch of pico optimization

Let’s focus on interferon-hi vs interferon-low samples
### Identify interesting

last_batch = c(300312389, 304012699, 304017553, 304020298, 304020362,
               340224808, 340233896, 340239789, 340239790, 340239805)
good_samples = mp_des[, ((!is.na(mp_des$RIN) & mp_des$RIN >= 7) & 
                    mp_des$STAR_mqc_generalstats_star_uniquely_mapped_percent >= 30 &
                    mp_des$featureCounts_mqc_generalstats_featurecounts_percent_assigned >= 30) &
                    mp_des$RNA_concentration_pg_ul >= 125]
remaining_interesting = setdiff(good_samples$sample, last_batch)
interesting_metadata = subset(total_umap, sample %in% remaining_interesting)
table(interesting_metadata$pna_type)
ggplot(interesting_metadata, aes(x = pna_type, y = AEpurple)) +
  geom_boxplot()
selection = interesting_metadata %>% 
  filter(pna_type != "Other Pneumonia" | sample == 340235110) %>% 
  dplyr::select(sample, tube_loc_macrophRNA_boxID, RNA_concentration_pg_ul) %>% 
  mutate(dilution = ifelse((250 / RNA_concentration_pg_ul) < 0.4,
                           yes = round(1 / (250 / RNA_concentration_pg_ul) / 5) * 5,
                           no = 1)) %>% 
  mutate(vol_for_250_pg = round(250 / RNA_concentration_pg_ul * dilution, digits = 2))
write.csv(selection, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200713_pico_opt_batch2.csv")
selection

Conclusions

Output data for posterity

final_counts_raw = counts(mp_des, normalized = F)

#clean metadata for safe sharing
final_md_safe = colData(mp_des) %>% 
  as.data.frame() %>% 
  dplyr::select(sample, age, sex, diagnosis = pna_type, 
                day_of_ventilation = finite_day_of_intubation, study_id)
#convert script IDs to new identifiers
id_conv = data.frame(script_id = sample(unique(final_md_safe$study_id))) %>% #shuffle IDs first
  mutate(anonymized_patient_id = sprintf("%04d", 1:nrow(id_conv)))
#add back to md
final_md_safe = left_join(final_md_safe, id_conv, by = c("study_id" = "script_id")) %>% 
  dplyr::select(-study_id)

write.csv(final_counts_raw, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/GEO_output/200724_raw_counts_geo.csv")
write.csv(final_md_safe, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/GEO_output/200724_deidentified_metadata_geo.csv")

Export supplemental files

DEA

all_comparisons = combn(levels(mp_des$Diagnosis), 2, simplify = F)
names(all_comparisons) = vapply(all_comparisons, function(x){
  return(paste0(x[1], " vs ", x[2]))}, "char")
dea_hits = lapply(all_comparisons, function(x){
  hits = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", x[1], x[2]),
                                  alpha = 0.05,
                                  parallel = T)) %>% 
    rownames_to_column("ensembl_gene_id") %>% 
    left_join(., gene_conv) %>% 
    arrange(padj)
  return(hits)})
names(dea_hits) = names(all_comparisons)
saveRDS(dea_hits, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/GEO_output/200728_bulk_dea_complete.rds")

Export as single excel file

output_genes = cov2_kmeans_clustered$genes %>% 
  dplyr::select(ensembl_gene_id = gene, cluster, external_gene_name) %>% 
  arrange(cluster)
names(dea_hits) = gsub("Healthy_Control", "HC", names(dea_hits))
names(dea_hits) = gsub("Other_Viral_Pneumonia", "OVP", names(dea_hits))
names(dea_hits) = gsub("Other_Pneumonia", "OP", names(dea_hits))
names(dea_hits) = gsub("Non_Pneumonia_Control", "NPC", names(dea_hits))
names(dea_hits) = gsub("COVID_19", "COVID-19", names(dea_hits))
all_sheets = c(list("k-means genes" = output_genes,
                    "k-means GO enrichment" = cov2_kmeans_clustered$go_df),
               dea_hits)
write.xlsx(x = all_sheets, 
           file = "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200728_bulk_supplmental_data.xlsx")

Assemble figures

Figure 3

fig3_heatmap = cov2_kmeans_clustered$plot
fig3_heatmap_gg = as.ggplot(fig3_heatmap)
viral_expression_heatmap_gg = as.ggplot(viral_expression_heatmap)
module_cor_heatmap_vent_gg = as.ggplot(module_cor_heatmap_vent)
Error in as.grob(plot) : object 'module_cor_heatmap_vent' not found

Figure S3

Marker genes

marker_gene_plot = ggplot(s3_counts, aes(x = Diagnosis, y = count, fill = Diagnosis)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) +
  geom_jitter(width = 0.25) +
  scale_y_continuous(trans = "log10") +
  scale_fill_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non_Pneumonia_Control" = fig2_pal[2],
                               "COVID_19" = fig2_pal[1],
                               "Other_Viral_Pneumonia" = fig2_pal[3],
                               "Other_Pneumonia" = fig2_pal[4])) +
  scale_x_discrete(labels = c("Healthy_Control" = "Healthy\nControl",
                               "Non_Pneumonia_Control" = "Non-Pneumonia\nControl",
                               "COVID_19" = "COVID-19",
                               "Other_Viral_Pneumonia" = "Other Viral\nPneumonia",
                               "Other_Pneumonia" = "Other\nPneumonia")) +
  xlab("") +
  ylab("Gene Counts") +
  facet_wrap(~gene_name, scale = "free_y", ncol = 3) +
  geom_signif(inherit.aes = F, 
              data = gene_comps,
              aes(xmin = numerator, xmax = denominator, annotations = label, y_position = y_log10),
              tip_length = 0,
              manual=TRUE,
              family = "Arial",
              textsize = 4) +
theme_bw(base_family = "Arial", base_size = 32) +
theme(legend.position = "none",
         text = element_text(family = "Arial"),
         axis.text.x = element_blank(),
         axis.ticks.x = element_blank(),
         plot.title = element_text(hjust = 0.5),
         strip.background = element_blank())
Ignoring unknown aesthetics: xmin, xmax, annotations, y_position
cov2_kmeans_noclustering = readRDS("/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_k_means_unclustered.rds")
coverage_plot = readRDS("/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200803_cov2_coverage_plot.rds")
figS3_heatmap = cov2_kmeans_noclustering$plot
figS3_heatmap_gg = as.ggplot(figS3_heatmap)

layout = "ABB\nABB\nABB\nABB\n#BB\nCBB\nDBB"
bulk_plot_fig3 = figS3_heatmap_gg +
  marker_gene_plot +
  sars_time_cor +
  coverage_plot +
    plot_layout(design = layout) +
    plot_annotation(tag_levels = 'a') & theme(plot.tag = element_text(size = 48))

bulk_plot_fig3

Figure S3

1
[1] 1
md = as.data.frame(colData(mp_des))
col_types = unlist(lapply(md, class))
list_cols = names(col_types[col_types == "AsIs"])
safe_md = md %>% 
  dplyr::select(-c(all_of(list_cols))) %>% 
  as.data.frame()
write.csv(safe_md, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200730_bulk_mp_metadata.csv")
LS0tCnRpdGxlOiAiU0NSSVBUIEJ1bGsgSGlnaC1MZXZlbCBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBHb2FscyAgIAoxLiBJZGVudGlmeSB0cmFuc2NyaXB0aW9uYWwgcGF0dGVybnMgaW4gQU0gYXNzb2NpYXRlZCB3aXRoIElBViwgQ09WSUQtMTksIGFuZCBjb21tb24gdG8gYm90aCAgIAoyLiBEZXRlcm1pbmUgc291cmNlIG9mIElMNiBhbmQgSUwxQiBpbiB0aGUgbHVuZyAoaWYgcG9zc2libGUpICAgCiAgIAojIFNldHVwICAgCiMjIExvYWQgcGFja2FnZXMgICAKYGBge3Igc2V0dXB9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3Bsb3RpZnkpCmxpYnJhcnkoZ2dzaWduaWYpCmxpYnJhcnkoQ2Fpcm8pCmxpYnJhcnkoREVTZXEyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KHV3b3QpCmxpYnJhcnkoV0dDTkEpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkodG9wR08pCmxpYnJhcnkoR08uZGIpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGRvUGFyYWxsZWwpCmxpYnJhcnkoYmlvbWFSdCkKbGlicmFyeShvcGVueGxzeCkKcmVnaXN0ZXJEb1BhcmFsbGVsKG1ha2VDbHVzdGVyKDEyKSkKcmVnaXN0ZXIoTXVsdGljb3JlUGFyYW0oMTIpKQpvcHRpb25zKGdzdWJmbi5lbmdpbmUgPSAiUiIpCnNldC5zZWVkKDEyMzQ1KQpzb3VyY2UoIn4vdXRpbHMvUi9wcmV0dHlfTUFfcGxvdC5SIikKc291cmNlKCJ+L3V0aWxzL1Iva19tZWFuc19maWd1cmUuUiIpCnNvdXJjZSgifi91dGlscy9SL3Bsb3RQQ0FfbWFudWFsLlIiKQpmaWcyX3BhbCA9IHBhbF9ucGcoIm5yYyIpKDkpCgpzZXNzaW9uSW5mbygpCmBgYAoKIyMgSW1wb3J0IGRhdGEgICAKYGBge3J9Cm1wID0gcmVhZFJEUygiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX3NjcmlwdF9idWxrX2Rlc19ub19oVVJOQS5yZHMiKQptcCRjb3ZpZF9jb25maXJtZWQgPSBmYWN0b3IobXAkY292aWRfY29uZmlybWVkKQptcCRzZXggPSBmYWN0b3IobXAkZ2VuZGVyKQoKI3NldCB1cCBmb3IgY29tcGFyaXNvbiBieSBkaWFnbm9zaXMKbXAkRGlhZ25vc2lzID0gZ3N1YigiLXwgIiwgIl8iLCBhcy5jaGFyYWN0ZXIobXAkcG5hX3R5cGUpKQptcCREaWFnbm9zaXMgPSBmYWN0b3IobXAkRGlhZ25vc2lzLCAKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhlYWx0aHlfQ29udHJvbCIsICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiLCAiQ09WSURfMTkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIsICJPdGhlcl9QbmV1bW9uaWEiKSkKbXAkbmV1dHJvcGhpbGljID0gbXAkcGVyY2VudF9uZXV0cm9waGlscyA+IDUwCiNmb3IgbW9kZWxpbmcsIGV0YwptcCRmaW5pdGVfZGF5X29mX2ludHViYXRpb24gPSBtcCRkYXlfb2ZfaW50dWJhdGlvbgptcCRmaW5pdGVfZGF5X29mX2ludHViYXRpb25baXMuaW5maW5pdGUobXAkZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uKV0gPSBOQQptcCRkYXkwX3NhbXBsZSA9IGZhY3RvcihtcCRkYXlfb2ZfaW50dWJhdGlvbiA+PSAwICYgbXAkZGF5X29mX2ludHViYXRpb24gPD0yKQptcCRkYXkwX3NhbXBsZVtpcy5uYShtcCRkYXkwX3NhbXBsZSldID0gRkFMU0UKZGVzaWduKG1wKSA9IGFzLmZvcm11bGEoIn4gRGlhZ25vc2lzIikKbWV0YWRhdGEgPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEobXApKQpgYGAgICAKICAgCiMjIFN1bW1hcnkgc3RhdHMgICAKIyMjIE51bWJlciBvZiBzYW1wbGVzIG92ZXJhbGwgICAKYGBge3J9CnRhYmxlKG1wJGNvdmlkX2NvbmZpcm1lZCwgdXNlTkEgPSAiYWx3YXlzIikKdGFibGUobXAkcG5hX3R5cGUsIHVzZU5BID0gImFsd2F5cyIpCmBgYCAgIAogICAKIyMjIE51bWJlciBvZiBwYXRpZW50cyAgIApgYGB7cn0KYnVsa19wYXRpZW50cyA9IGNvbERhdGEobXApICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfaWQsIGNvdmlkX2NvbmZpcm1lZCwgcG5hX3R5cGUpICU+JSAKICB1bmlxdWUoKQp0YWJsZShidWxrX3BhdGllbnRzJGNvdmlkX2NvbmZpcm1lZCkKdGFibGUoYnVsa19wYXRpZW50cyRwbmFfdHlwZSkKYGBgCgoKIyMjIE51bWJlciBvZiBzZXJpYWwgc2FtcGxlcyAgIApgYGB7cn0Kbl9zYW1wbGVzID0gdGFibGUobWV0YWRhdGEkcGF0aWVudF9pZCkKc2VyaWFsX3BhdGllbnRzID0gbmFtZXMobl9zYW1wbGVzW25fc2FtcGxlcyA+IDFdKQpsZW5ndGgoc2VyaWFsX3BhdGllbnRzKQpgYGAgICAKICAgCiMjIyBEaXN0cmlidXRpb24gb2YgZGF5cyAgIApgYGB7cn0KZ2dwbG90KG1ldGFkYXRhLCBhZXMoeCA9IGRheV9vZl9pbnR1YmF0aW9uKSkgKwogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiZG9kZ2VyYmx1ZTQiKQpgYGAKICAgCiMjIFBDQSAgIAojIyMgQ2FsY3VsYXRlIGFuZCBvcmdhbml6ZSAgIApgYGB7cn0KbXBfdnN0ID0gdnN0KG1wLCBuc3ViID0gMzAwMCwgZml0VHlwZSA9ICJsb2NhbCIpICNrbm93IGZyb20gbGF0ZXIgdGhhdCBsb2NhbCBpcyBiZXN0Cm1wX2NvdW50cyA9IGNvdW50cyhlc3RpbWF0ZVNpemVGYWN0b3JzKG1wKSwgbm9ybWFsaXplZCA9IFQpCnBjYV9kYXRhID0gcGxvdFBDQV9tYW51YWwobXBfdnN0LAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygiY292aWRfY29uZmlybWVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGNzID0gMTApCnBjYV9kYXRhJGRhdGEgPSBsZWZ0X2pvaW4ocGNhX2RhdGEkZGF0YSwKICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShjb2xEYXRhKG1wKSksCiAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygibmFtZSIgPSAic2FtcGxlIiwgImNvdmlkX2NvbmZpcm1lZCIpKQoKI21lcmdlIGNvdW50cyBhbmQgcGNhIGRhdGEKZ2VuZV9jb252ID0gYXMuZGF0YS5mcmFtZShyb3dEYXRhKG1wKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiZW5zZW1ibF9nZW5lX2lkIikKbWVyZ2VfY291bnRzID0gbXBfY291bnRzICU+JSAKICB0KCkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gIm5hbWUiKQoKI21lcmdlIHRvZ2V0aGVyIGZvciBmZWF0dXJlcGxvdCBkYXRhc2V0CmZwX2RhdGEgPSBsZWZ0X2pvaW4ocGNhX2RhdGEkZGF0YSwgbWVyZ2VfY291bnRzLCBieSA9ICJuYW1lIikKYGBgCgojIyMgSG93IG1hbnkgUENzPyAgIApgYGB7cn0KI3NjcmVlIHBsb3QgICAKZnZpel9laWcocGNhX2RhdGEkcGNhLCAKICAgICAgICAgYmFyZmlsbCA9ICJkb2RnZXJibHVlNCIsIAogICAgICAgICB4bGFiID0gIlByaW5jaXBhbCBDb21wb25lbnQiLAogICAgICAgICB5bGFiID0gIlBlcmNlbnQgVmFyaWFuY2UgRXhwbGFpbmVkIiwgCiAgICAgICAgIG1haW4gPSAiIiwKICAgICAgICAgbmNwID0gNTAsCiAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9idygpLAogICAgICAgICBhZGRsYWJlbHMgPSBUKSAjNC01IFBDcyB3aWxsIGRvIGl0CmBgYAogICAKIyMjIEV4YW1pbmUgbG9hZGluZ3MgICAKYGBge3J9CmxvYWRpbmdzID0gcGNhX2RhdGEkcGNhJHJvdGF0aW9uICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIHJpZ2h0X2pvaW4oZ2VuZV9jb252LCAuKQpgYGAKCiAgIAojIyMgUEMxOiBNb0FNIENoYXJhY3RlciAgIApgYGB7cn0KZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBzaGFwZSA9IGNvdmlkX2NvbmZpcm1lZCwgY29sb3IgPSBwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykKZmFicDRfcGxvdCA9IGdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBsb2cyKEVOU0cwMDAwMDE3MDMyMykpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG5hbWUgPSAiTG9nMihGQUJQNCBDb3VudHMpIikKc3BwMV9wbG90ID0gZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGxvZzIoRU5TRzAwMDAwMTE4Nzg1KSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMobmFtZSA9ICJMb2cyKFNQUDEgQ291bnRzKSIpCmZhYnA0X3Bsb3QgKyBzcHAxX3Bsb3QKYGBgICAgCiAgICAKIyMjIFBDMjogUGF0dGVybnMgb2YgYWN0aXZhdGlvbiAoYWxzbyBieSBtaWxpZXUpICAgCmBgYHtyfQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gY292aWRfY29uZmlybWVkLCBjb2xvciA9IENfUmVhY3RpdmVfUHJvdGVpbikpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gY292aWRfY29uZmlybWVkLCBjb2xvciA9IExESCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gY292aWRfY29uZmlybWVkLCBjb2xvciA9IEZFUlJJVElOKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpCmluaGJhX3Bsb3QgPSBnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gbG9nMihFTlNHMDAwMDAxMjI2NDEpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhuYW1lID0gIkxvZzIoSU5IQkEpIikKaWwxYl9wbG90ID0gZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGxvZzIoRU5TRzAwMDAwMTI1NTM4KSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMobmFtZSA9ICJMb2cyKElMMWIpIikKYGBgCkFmdGVyIGFkZGluZyBoZWFsdGh5IGNvbnRyb2xzIHRoaXMgaXMgbG9uZ2VyIHRydWUuICAgCgogICAKIyMjIFBDMzogTWFsZS9mZW1hbGU/ICAgCmBgYHtyfQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzIsIHkgPSBQQzMsIGNvbG9yID0gZ2VuZGVyKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpCnhpc3RfcGxvdCA9IGdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMiwgeSA9IFBDMywgY29sb3IgPSBsb2cyKEVOU0cwMDAwMDIyOTgwNykpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG5hbWUgPSAiTG9nMihYSVNUKSIpCmBgYCAgIApOb3QgcmVhbGx5ICAgCiAgIAojIyMgQ29uZGl0aW9uCmBgYHtyfQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gRGlhZ25vc2lzKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBzdGF0X2VsbGlwc2UoKQpgYGAgICAKICAgCiMjIyBEYXkgb2YgaW50dWJhdGlvbgpgYGB7cn0KZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGxvZzIoZGF5X29mX2ludHViYXRpb24pKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpCmBgYCAgIApObyBjbGVhciBzZXBhcmF0aW9uLiAgIAogICAKIyMgRGV0ZXJtaW5lIGJlc3QgZGlzcGVyc2lvbiBlc3RpbWF0ZXMgICAKIyMjIFBhcmFtZXRyaWMgICAKYGBge3J9CiNub3RlOiBERVNlcSBpcyByZWZpdHRpbmcgZmFyIHRvbyBtYW55IGdlbmVzLiBOZWVkIHRvIHR1cm4gdGhpcyBvZmYuCm1wX2Rlc19wYXJhbWV0cmljID0gREVTZXEobXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGZpdFR5cGUgPSAicGFyYW1ldHJpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgIG1pblJlcGxpY2F0ZXNGb3JSZXBsYWNlID0gSW5mKQpwbG90RGlzcEVzdHMobXBfZGVzX3BhcmFtZXRyaWMsIGNleCA9IDAuMSkKYGBgICAgCiAgIApUaGlzIGZpdCByZWFsbHkgaXNuJ3QgYmFkLCBidXQgb3ZlcmVzdGltYXRlcyBhdCBsb3dlciBleHByZXNzaW9uIChwcm9iYWJseSBub3QgYSBodWdlIGRlYWwpLiAgIAogICAgCiMjIyBMb2NhbApgYGB7cn0KbXBfZGVzX2xvY2FsID0gREVTZXEobXAsCiAgICAgICAgICAgICAgICAgICAgIGZpdFR5cGUgPSAibG9jYWwiLAogICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQsCiAgICAgICAgICAgICAgICAgICAgIG1pblJlcGxpY2F0ZXNGb3JSZXBsYWNlPUluZikKcGxvdERpc3BFc3RzKG1wX2Rlc19sb2NhbCwgY2V4ID0gMC4xKQoKbXBfZGVzID0gbXBfZGVzX2xvY2FsCnJtKG1wX2Rlc19sb2NhbCwgbXBfZGVzX3BhcmFtZXRyaWMpCmBgYCAgClN0aWxsIG5vdCBwZXJmZWN0LCBidXQgYSBsb3QgYmV0dGVyLiAgIAogICAKYGBge3J9CiN1c2VkIGEgZmV3IHRpbWVzIGxhdGVyOyBzYWZlc3QgdG8gcHV0IGhlcmUKI2lkZW50aWZ5IGluZmVjdGVkIHNhbXBsZXMKbm9uX2h1bWFuX2dlbmVzID0gc3Vic2V0KGdlbmVfY29udiwgIShncmVwbCgiXkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKSkgI2h1bWFuIGdlbmVzIGFsbCBoYXZlIHRoaXMgcHJlZml4Cm5vbl9odW1hbl9nZW5lcyRnZW5lX25hbWVbbm9uX2h1bWFuX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCA9PSAiZ2VuZS1VSjk5X3M2Z3AxIl0gPSAiTkEiICNuZXVyYW1pbmlkYXNlIHdhcyBtaXNyZWFkCm5vbl9odW1hbl9nZW5lcyR2aXJ1cyA9IGZhY3RvcihpZmVsc2UoZ3JlcGwoIlVKOTkiLCBub25faHVtYW5fZ2VuZXMkZW5zZW1ibF9nZW5lX2lkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9ICJJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAiU0FSUy1Db1YtMiIpKQpjb3YyX2dlbmVzID0gc3Vic2V0KG5vbl9odW1hbl9nZW5lcywgZ3JlcGwoIlNBUlN8R1UyODAiLCBlbnNlbWJsX2dlbmVfaWQpKQppYXZfZ2VuZXMgPSBzdWJzZXQobm9uX2h1bWFuX2dlbmVzLCBncmVwbCgiVUo5OSIsIGVuc2VtYmxfZ2VuZV9pZCkpCmZsdV9jb3VudHMgPSBjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gVClbaWF2X2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwgXQpmbHVfZGV0ZWN0ZWQgPSBjb2xuYW1lcyhmbHVfY291bnRzWywgY29sU3VtcyhmbHVfY291bnRzKSA+IDBdKQpjb3YyX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKVtjb3YyX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwgXQpjb3YyX2RldGVjdGVkID0gY29sbmFtZXMoY292Ml9jb3VudHNbLCBjb2xTdW1zKGNvdjJfY291bnRzKSA+IDBdKQptcF9kZXMkc2Fyc19jb3YyX2RldGVjdGVkID0gZmFjdG9yKG1wX2RlcyRzYW1wbGUgJWluJSBjb3YyX2RldGVjdGVkKQptcF9kZXMkaWF2X2gxbjFfZGV0ZWN0ZWQgPSBmYWN0b3IobXBfZGVzJHNhbXBsZSAlaW4lIGZsdV9kZXRlY3RlZCkKCiMjIFJlcGxpY2F0aW5nIENvVjIgc2FtcGxlcwojIyMgb3ZlcmFsbAphbnRpc2Vuc2VfY291bnRzID0gY292Ml9jb3VudHNbIlNBUlNfQ29WXzJfYW50aXNlbnNlX2dlbm9tZSIsIF0Kc2Vuc2VfY291bnRzID0gY292Ml9jb3VudHNbMjpucm93KGNvdjJfY291bnRzKSwgXQpyZXBsaWNhdGluZ19jb3YyID0gaW50ZXJzZWN0KG5hbWVzKGFudGlzZW5zZV9jb3VudHMpW2FudGlzZW5zZV9jb3VudHMgPiAwXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhzZW5zZV9jb3VudHNbLCBjb2xTdW1zKHNlbnNlX2NvdW50cykgPiAwXSkpCiMjIyBqdXN0IGNvdmlkCnBlcmNlbnRfZGV0ZWN0ZWRfY292aWQgPSBsZW5ndGgodW5pcXVlKHN1YnNldChtZXRhZGF0YSwgc2FtcGxlICVpbiUgY292Ml9kZXRlY3RlZCAmIGNvdmlkX2NvbmZpcm1lZCA9PSBUUlVFKSRzdHVkeV9pZCkpIC8gbGVuZ3RoKHVuaXF1ZShzdWJzZXQobWV0YWRhdGEsIGNvdmlkX2NvbmZpcm1lZCA9PSBUUlVFKSRzdHVkeV9pZCkpICogMTAwCnBlcmNlbnRfZGV0ZWN0ZWRfY292aWQKcGVyY2VudF9yZXBsaWNhdGluZ19jb3ZpZCA9IGxlbmd0aCh1bmlxdWUoc3Vic2V0KG1ldGFkYXRhLCBzYW1wbGUgJWluJSByZXBsaWNhdGluZ19jb3YyICYgY292aWRfY29uZmlybWVkID09IFRSVUUpJHN0dWR5X2lkKSkgLyBsZW5ndGgodW5pcXVlKHN1YnNldChtZXRhZGF0YSwgY292aWRfY29uZmlybWVkID09IFRSVUUpJHN0dWR5X2lkKSkgKiAxMDAKcGVyY2VudF9yZXBsaWNhdGluZ19jb3ZpZAoKcGVyY2VudF9yZXBsaWNhdGluZ19jb3ZpZCAvIHBlcmNlbnRfZGV0ZWN0ZWRfY292aWQgKiAxMDAKYGBgCiAgICAgIAojIyBTYW5pdHkgY2hlY2tzICAKIyMjIFNBUlMtQ29WLTIgICAKRG9lcyBleHByZXNzaW9uIG9mIHZpcmFsIGdlbmVzIGNvcnJlbGF0ZSB3aXRoIGNvdmlkIGRpYWdub3Npcz8gICAKYGBge3J9CmNvdjJfY291bnRzID0gbGFwcGx5KGNvdjJfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBmdW5jdGlvbih4KXsKICBjb3VudHMgPSBwbG90Q291bnRzKG1wLAogICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IHgsCiAgICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9ICJEaWFnbm9zaXMiLAogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgcGMgPSBUKQogIGNvdW50cyRnZW5lID0geAogIHJldHVybihjb3VudHMpfSkKY292Ml9jb3VudHMgPSBiaW5kX3Jvd3MoY292Ml9jb3VudHMpCgpnZ3Bsb3QoY292Ml9jb3VudHMsIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gY291bnQsIGZpbGwgPSBnZW5lKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBzY2FsZV95X2xvZzEwKCkKYGBgICAgCk5vdyB0aGF0IHdlIGhhdmUgYWxsIG9mIHRoZSBuZWNlc3NhcnkgbWV0YWRhdGEsIHRoaXMgbG9va3MgZmFudGFzdGljLiAgCiAgIAoKICAgICAgCiMjIyBEbyBjb3VudHMgY2x1c3RlciBieSB2aXJ1cyBhbmQgZGlhZ25vc2lzPyAgIApgYGB7cn0KdmlyYWxfY291bnRzID0gY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpIAp2aXJhbF9jb3VudHMgPSB2aXJhbF9jb3VudHNbbm9uX2h1bWFuX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwgXQp2aXJhbF9jb3VudHMgPSBsb2cxMCh2aXJhbF9jb3VudHMgKyAwLjUpCgp2aXJ1c19kZXRlY3Rpb24gPSB2ZWN0b3IobW9kZSA9ICJjaGFyYWN0ZXIiLCBsZW5ndGggPSBuY29sKG1wX2RlcykpCmZvcihpIGluIDE6bmNvbChtcF9kZXMpKQp7CiAgaGFzX2NvdmlkID0gbXBfZGVzJGNvdmlkX2NvbmZpcm1lZFtpXSA9PSBUUlVFCiAgaGFzX2lhdl9oMW4xID0gbXBfZGVzJElORkxVRU5aQV9BX0gxXzIwMDlbaV0gPT0gIlBvc2l0aXZlIgogIGhhc19vdGhlcl9jb3JvbmF2aXJ1cyA9IG1wX2RlcyRhbnlfY29yb25hdmlydXNfbm9uX2NvdmlkW2ldID09IFRSVUUKICAjcmVjb2RlIE5BIGFzIEZBTFNFIGZvciBzYWZldHkKICBpZihpcy5uYShoYXNfaWF2X2gxbjEpKSAKICB7CiAgICBoYXNfaWF2X2gxbjEgPSBGQUxTRQogIH0KICBpZihpcy5uYShoYXNfb3RoZXJfY29yb25hdmlydXMpKSAKICB7CiAgICBoYXNfb3RoZXJfY29yb25hdmlydXMgPSBGQUxTRQogIH0KICAKICBpZihoYXNfY292aWQgPT0gVFJVRSAmJiBoYXNfaWF2X2gxbjEgPT0gVFJVRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gVFJVRSkKICB7CiAgICB2aXJ1c19kZXRlY3Rpb25baV0gPSAiU0FSUy1Db1YtMiAmIE90aGVyIENvcm9uYXZpcnVzICYgSW5mbHVlbnphIEEvQ2FsaWZvcm5pYS8wNy8yMDA5IgogIH0gZWxzZSBpZihoYXNfY292aWQgPT0gVFJVRSAmJiBoYXNfaWF2X2gxbjEgPT0gRkFMU0UgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IEZBTFNFKQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJTQVJTLUNvVi0yIgogIH0gZWxzZSBpZihoYXNfY292aWQgPT0gRkFMU0UgJiYgaGFzX2lhdl9oMW4xID09IFRSVUUgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IEZBTFNFKQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiCiAgfSBlbHNlIGlmKGhhc19jb3ZpZCA9PSBGQUxTRSAmJiBoYXNfaWF2X2gxbjEgPT0gRkFMU0UgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IFRSVUUpCiAgewogICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJPdGhlciBDb3JvbmF2aXJ1cyIKICB9IGVsc2UgaWYoaGFzX2NvdmlkID09IFRSVUUgJiYgaGFzX2lhdl9oMW4xID09IFRSVUUgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IEZBTFNFKQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJTQVJTLUNvVi0yICYgSW5mbHVlbnphIEEvQ2FsaWZvcm5pYS8wNy8yMDA5IgogIH0gZWxzZSBpZihoYXNfY292aWQgPT0gVFJVRSAmJiBoYXNfaWF2X2gxbjEgPT0gRkFMU0UgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IFRSVUUpCiAgewogICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIlNBUlMtQ29WLTIgJiBPdGhlciBDb3JvbmF2aXJ1cyIKICB9IGVsc2UgaWYoaGFzX2NvdmlkID09IEZBTFNFICYmIGhhc19pYXZfaDFuMSA9PSBUUlVFICYmIGhhc19vdGhlcl9jb3JvbmF2aXJ1cyA9PSBUUlVFKQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJPdGhlciBDb3JvbmF2aXJ1cyAmIEluZmx1ZW56YSBBL0NhbGlmb3JuaWEvMDcvMjAwOSIKICB9IGVsc2UKICB7CiAgICB2aXJ1c19kZXRlY3Rpb25baV0gPSBOQQogIH0KfQptcF9kZXMkZGV0ZWN0ZWRfdmlydXNlcyA9IGZhY3Rvcih2aXJ1c19kZXRlY3Rpb24pCiAgCmRpYWdub3Npc19hbm5vdGF0aW9uID0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKG1wX2RlcykpICU+JSAKICBkcGx5cjo6c2VsZWN0KERpYWdub3NpcyA9IGRldGVjdGVkX3ZpcnVzZXMpCmdlbmVfYW5ub3RhdGlvbiA9IG5vbl9odW1hbl9nZW5lcyAlPiUgCiAgcmVtb3ZlX3Jvd25hbWVzKCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoYFZpcmFsIE9yaWdpbmAgPSB2aXJ1cykKZ2VuZV9uYW1lcyA9IG5vbl9odW1hbl9nZW5lcyRnZW5lX25hbWUKZ2VuZV9uYW1lc1tnZW5lX25hbWVzID09ICJTQVJTX0NvVl8yX2FudGlzZW5zZV9nZW5vbWUiXSA9ICJBbnRpc2Vuc2UiCgp2aXJhbF9leHByZXNzaW9uX2hlYXRtYXAgPSBwaGVhdG1hcCh2aXJhbF9jb3VudHMsCiAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgY29sb3IgPSBpbmZlcm5vKDEwMCksCiAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBkaWFnbm9zaXNfYW5ub3RhdGlvbiwKICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGdlbmVfYW5ub3RhdGlvbiwKICAgICAgICBsYWJlbHNfcm93ID0gZ2VuZV9uYW1lcywKICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoRGlhZ25vc2lzID0gYygiU0FSUy1Db1YtMiIgPSBmaWcyX3BhbFsxXSwgIk90aGVyIENvcm9uYXZpcnVzIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW5mbHVlbnphIEEvQ2FsaWZvcm5pYS8wNy8yMDA5IiA9IGZpZzJfcGFsWzNdLCAiT3RoZXIgQ29yb25hdmlydXMgJiBJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiID0gZmlnMl9wYWxbNF0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFZpcmFsIE9yaWdpbmAgPSBjKCJTQVJTLUNvVi0yIiA9IGZpZzJfcGFsWzFdLCAiSW5mbHVlbnphIEEvQ2FsaWZvcm5pYS8wNy8yMDA5IiA9IGZpZzJfcGFsWzNdKSksCiAgICAgICAgYW5nbGVfY29sID0gNDUsIAogICAgICAgIGFubm90YXRpb25fbmFtZXNfcm93ID0gRiwgCiAgICAgICAgZm9udHNpemUgPSAyNCkKYGBgCiAgIAojIyMgUGF0aWVudCAxMTc0ICAgClRoaXMgcGF0aWVudCBhcHBhcmVudGx5IG1ldCBjcml0ZXJpYSBmb3IgQ09WSUQgd2VsbCBiZWZvcmUgdGhlIGZpcnN0IGtub3duIGNhc2VzIGluIENoaWNhZ28gICAKYGBge3J9CmNvdjJfY291bnRzID0gY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpW2NvdjJfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBdCnNhbXBsZXNfMTE3NCA9IG1wX2RlcyRzdHVkeV9pZCA9PSAiMTE3NCIKc2FtcGxlc18xMTc0W2lzLm5hKHNhbXBsZXNfMTE3NCldID0gRkFMU0UKdHViZXNfMTE3NCA9IG1wX2RlcyRzYW1wbGVbc2FtcGxlc18xMTc0XQpjb3YyX2NvdW50c18xMTc0ID0gY292Ml9jb3VudHNbLCB0dWJlc18xMTc0XQpjb3YyX2NvdW50c18xMTc0CmBgYApObyBkZXRlY3Rpb24sIGF0IGxlYXN0IGluIG1hY3JvcGhhZ2VzLiAgIAogICAKIyMjIERvIENvVjIgcmVhZHMgZGVjcmVhc2Ugb3ZlciB0aW1lPyAgIApDaGVja2luZyBmb3IgdmlyYWwgY2xlYXJhbmNlICAgCmBgYHtyfQpjb3ZpZF9jYXNlcyA9IG1wX2Rlc1ssIG1wX2RlcyRjb3ZpZF9jb25maXJtZWQgPT0gVFJVRV0KY292aWRfY291bnRzID0gY291bnRzKGNvdmlkX2Nhc2VzLCBub3JtYWxpemVkID0gVCkKY292aWRfY291bnRzID0gY292aWRfY291bnRzW2NvdjJfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBdCgpjb3ZpZF9jb3VudHMgPSBjb3ZpZF9jb3VudHMgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJnZW5lIikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gIjM0MDE5NTA0NiI6IjM0MDIzOTg2NyIsCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNhbXBsZSIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJDb3VudHMiKSAlPiUgCiAgbGVmdF9qb2luKC4sIG5vbl9odW1hbl9nZW5lcywgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWMoZ2VuZSwgdmlydXMpKSAlPiUgCiAgbGVmdF9qb2luKC4sIGFzLmRhdGEuZnJhbWUoY29sRGF0YShtcF9kZXMpKSwgYnkgPSAic2FtcGxlIikKCmdncGxvdChjb3ZpZF9jb3VudHMsIGFlcyh4ID0gZGF5X29mX2ludHViYXRpb24sIHkgPSBDb3VudHMpKSArCiAgZmFjZXRfd3JhcCh+IGdlbmVfbmFtZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRikKYGBgICAgClVuZm9ydHVuYXRlbHkgdGhpcyBpcyBzb21ld2hhdCBiaW5hcml6ZWQuIEJldHRlciB0byB0cmVhdCBpdCBhcyBzdWNoLiAgIAogICAKYGBge3J9CmNvdmlkX2NvdW50c19iaW5hcml6ZWQgPSBjb3ZpZF9jb3VudHMgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIAogIG11dGF0ZShhbGxfdmlyYWxfY291bnRzID0gc3VtKENvdW50cykpICU+JSAKICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgYWxsX3ZpcmFsX2NvdW50cywgZGF5X29mX2ludHViYXRpb24pICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgbXV0YXRlKHZpcnVzX2RldGVjdGVkID0gYWxsX3ZpcmFsX2NvdW50cyA+IDApCgp0aW1lX2NvciA9IGNvci50ZXN0KGNvdmlkX2NvdW50c19iaW5hcml6ZWQkYWxsX3ZpcmFsX2NvdW50cywgY292aWRfY291bnRzX2JpbmFyaXplZCRkYXlfb2ZfaW50dWJhdGlvbiwgbWV0aG9kID0gInNwZWFybWFuIikKdGltZV9jb3JfcmhvID0gcm91bmQodGltZV9jb3IkZXN0aW1hdGUsIGRpZ2l0cyA9IDIpCgpzYXJzX3RpbWVfY29yID0gZ2dwbG90KGNvdmlkX2NvdW50c19iaW5hcml6ZWQsIGFlcyh4ID0gZGF5X29mX2ludHViYXRpb24sIHkgPSBhbGxfdmlyYWxfY291bnRzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikgKwogIHhsYWIoIkRheSBvZiBNZWNoYW5pY2FsIFZlbnRpbGF0aW9uIikgKwogIHlsYWIoIlNBUlMtQ29WLTIgQ291bnRzIikgKwogIGdlb21fc21vb3RoKHNlID0gRiwgY29sb3IgPSBmaWcyX3BhbFsyXSkgKwogIHRoZW1lX2J3KGJhc2VfZmFtaWx5ID0gIkFyaWFsIiwgYmFzZV9zaXplID0gMzIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJBcmlhbCIpKSArCiAgYW5ub3RhdGUoeCA9IDMwLCB5ID0gNWU0LCBsYWJlbCA9IHBhc3RlKCLPgSA9ICIsIHRpbWVfY29yX3JobyksIHNpemUgPSAxMCwgZ2VvbSA9ICJ0ZXh0IikKc2Fyc190aW1lX2NvcgpgYGAKCiMjIEV4cG9ydCBmb3IgbW9kZWxpbmcgY29yZSAgIApgYGB7ciBldmFsPUZBTFNFfQpjb2xfdHlwZXMgPSB1bmxpc3QobGFwcGx5KG1ldGFkYXRhLCBjbGFzcykpCmxpc3RfY29scyA9IG5hbWVzKGNvbF90eXBlc1tjb2xfdHlwZXMgPT0gIkFzSXMiXSkKc2FmZV9tZXRhZGF0YSA9IG1ldGFkYXRhICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jKGFsbF9vZihsaXN0X2NvbHMpKSkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQp3cml0ZS5jc3Yoc2FmZV9tZXRhZGF0YSwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvV29ya3NwYWNlL0NPVklEMTlfYmFsX21zLzIwMDcwOV9idWxrX21ldGFkYXRhLmNzdiIpCndyaXRlLmNzdihjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gRiksICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L1dvcmtzcGFjZS9DT1ZJRDE5X2JhbF9tcy8yMDA3MDlfYnVsa19jb3VudHNfcmF3LmNzdiIpCndyaXRlLmNzdihjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gVCksICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L1dvcmtzcGFjZS9DT1ZJRDE5X2JhbF9tcy8yMDA3MDlfYnVsa19jb3VudHNfZGVzZXEyX25vcm1hbGl6ZWQuY3N2IikKYGBgCiAgICAgIAojIyBXaGljaCBzYW1wbGVzIGFyZSB3b3J0aCBzZXF1ZW5jaW5nIGZ1cnRoZXI/ICAgCiMjIyBGaXJzdCBiYXRjaCAgIApgYGB7ciBldmFsPUZBTFNFfQpnb29kX3NhbXBsZXMgPSBtcF9kZXNbLCAoKCFpcy5uYShtcF9kZXMkUklOKSAmIG1wX2RlcyRSSU4gPj0gNykgJiAKICAgICAgICAgICAgICAgICAgICBtcF9kZXMkU1RBUl9tcWNfZ2VuZXJhbHN0YXRzX3N0YXJfdW5pcXVlbHlfbWFwcGVkX3BlcmNlbnQgPj0gMzAgJgogICAgICAgICAgICAgICAgICAgIG1wX2RlcyRmZWF0dXJlQ291bnRzX21xY19nZW5lcmFsc3RhdHNfZmVhdHVyZWNvdW50c19wZXJjZW50X2Fzc2lnbmVkID49IDMwKSAmCiAgICAgICAgICAgICAgICAgICAgbXBfZGVzJFJOQV9jb25jZW50cmF0aW9uX3BnX3VsID49IDEyNSB8CiAgICAgICAgICAgICAgICAgICAgKG1wX2RlcyRpYXZfaDFuMV9kZXRlY3RlZCA9PSBUUlVFIHwgbXBfZGVzJHNhcnNfY292Ml9kZXRlY3RlZCA9PSBUUlVFKV0KCnNlbGVjdGlvbl9kYXRhID0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGdvb2Rfc2FtcGxlcykpICU+JSAKICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgdGNfcHRfc3R1ZHlfaWQsIFJJTiwgU1RBUl9tcWNfZ2VuZXJhbHN0YXRzX3N0YXJfdW5pcXVlbHlfbWFwcGVkX3BlcmNlbnQsCiAgICAgICAgIGZlYXR1cmVDb3VudHNfbXFjX2dlbmVyYWxzdGF0c19mZWF0dXJlY291bnRzX3BlcmNlbnRfYXNzaWduZWQsIGlhdl9oMW4xX2RldGVjdGVkLCAKICAgICAgICAgc2Fyc19jb3YyX2RldGVjdGVkLCBjb3ZpZF9jb25maXJtZWQsIGJhdGNoLCBSTkFfY29uY2VudHJhdGlvbl9wZ191bCwgcG5hX3R5cGUpCnNlbGVjdGlvbl9kYXRhCmBgYCAgIApLZWVwZXJzOiAgIAotIDM0MDIyNDgwOCAoSUFWKQotIDMwNDAxNzU1MyAoSUFWICsgbGlrZWx5IGFub3RoZXIgY29yb25hdmlydXMpCi0gMzQwMjM5ODA1IChDb3YyKQotIDM0MDIzMzg5NiAoQ292MikKLSAzNDAyMzk3OTAgKENvdjIpCi0gMzQwMjM5Nzg5IChDb3YyKQotIDMwNDAxMjY5OSAoT3RoZXIgLS0gbGlrZWx5IGFub3RoZXIgY29yb25hdmlydXMpCi0gMzAwMzEyMzg5IChvdGhlcikKLSAzMDQwMjAzNjIgKG90aGVyKQogICAKYGBge3IgZXZhbD1GQUxTRX0Ka2VlcGVycyA9IHNlbGVjdGlvbl9kYXRhICU+JSAKICBkcGx5cjo6ZmlsdGVyKHNhbXBsZSAlaW4lIGMoMzA0MDIwMjk4LCAzNDAyMjQ4MDgsIDMwNDAxNzU1MywgMzQwMjM5ODA1LCAzNDAyMzM4OTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDM0MDIzOTc5MCwgMzQwMjM5Nzg5LCAzMDQwMTI2OTksIDMwMDMxMjM4OSwgMzA0MDIwMzYyKSkgJT4lIAogIG11dGF0ZSh2b2xfZm9yXzI1MF9wZyA9IHJvdW5kKDI1MCAvIFJOQV9jb25jZW50cmF0aW9uX3BnX3VsLCBkaWdpdHMgPSAzKSkKa2VlcGVycyRkaWx1dGlvbiA9IGlmZWxzZShrZWVwZXJzJHZvbF9mb3JfMjUwX3BnID4gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSBpZmVsc2Uoa2VlcGVycyR2b2xfZm9yXzI1MF9wZyA+IDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMjApKQprZWVwZXJzJGRpbHV0aW9uX3ZvbF9mb3JfMjUwX3BnID0gcm91bmQoMjUwIC8gKGtlZXBlcnMkUk5BX2NvbmNlbnRyYXRpb25fcGdfdWwgLyBrZWVwZXJzJGRpbHV0aW9uKSwgZGlnaXRzID0gMykKd3JpdGUuY3N2KGtlZXBlcnMsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA2MTJfcmVzZXF1ZW5jaW5nX3NhbXBsZXMuY3N2IikKa2VlcGVycwpgYGAgICAKICAgCiMgU2lnbmF0dXJlcyBhc3NvY2lhdGVkIHdpdGggU0FSUy1Db1YtMiAgIAojIyBTaW5nbGUgZ2VuZXMgICAKIyMjIElMNiAgIApgYGB7cn0KaWw2X2NvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDEzNjI0NCIsCiAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsCiAgICAgICAgICAgaW50Z3JvdXAgPSAiY292aWRfY29uZmlybWVkIiwKICAgICAgICAgICByZXR1cm5EYXRhID0gVCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2FtcGxlIikgJT4lIAogIGxlZnRfam9pbiguLCAKICAgICAgICAgICAgbWV0YWRhdGEsCiAgICAgICAgICAgIGJ5ID0gYygic2FtcGxlIiwgImNvdmlkX2NvbmZpcm1lZCIpKQoKY29yLnRlc3QoaWw2X2NvdW50cyRjb3VudCwgaWw2X2NvdW50cyRwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gpCmlsNl9wbG90ID0gZ2dwbG90KGlsNl9jb3VudHMsIGFlcyh4ID0gcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoLCB5ID0gY291bnQsIGNvbG9yID0gY292aWRfY29uZmlybWVkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIHlsYWIoIklMNiBDb3VudHMiKQpgYGAgICAKTGF0ZXIgY29uZmlybWVkIE5TRCBieSBncm91cC4gQ2xlYXJseSBjb3JyZWxhdGVzIHdpdGggTW9BTSBjaGFyYWN0ZXIuICAgICAgICAKICAgCiMjIyBJTDFiICAgCmBgYHtyfQppbDFiX2NvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDEyNTUzOCIsCiAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsCiAgICAgICAgICAgaW50Z3JvdXAgPSAiY292aWRfY29uZmlybWVkIiwKICAgICAgICAgICByZXR1cm5EYXRhID0gVCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2FtcGxlIikgJT4lIAogIGxlZnRfam9pbiguLCAKICAgICAgICAgICAgbWV0YWRhdGEsCiAgICAgICAgICAgIGJ5ID0gYygic2FtcGxlIiwgImNvdmlkX2NvbmZpcm1lZCIpKQoKY29yLnRlc3QoaWwxYl9jb3VudHMkY291bnQsIGlsMWJfY291bnRzJHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCkKaWwxYl9wbG90ID0gZ2dwbG90KGlsMWJfY291bnRzLCBhZXMoeCA9IHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCwgeSA9IGNvdW50LCBjb2xvciA9IGNvdmlkX2NvbmZpcm1lZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgc2NhbGVfeV9sb2cxMCgpICsgCiAgeWxhYigiSUwxYiBDb3VudHMiKQoKaWw2X3Bsb3QgLyBpbDFiX3Bsb3QKYGBgCkxhdGVyIGNvbmZpcm1lZCBzaWduaWZpY2FudGx5IGRvd25yZWd1bGF0ZWQsIGFjdHVhbGx5LiAgIAoKIyMgQmFzaWMgREVBICAgCiMjIyBHZW5lIGhpdHMgICAKICAgClZlcnN1cyBoZWFsdGh5IGNvbnRyb2xzICAgCmBgYHtyfQpjb3YyX3ZzX2hjX3Jlc3VsdHMgPSBhcy5kYXRhLmZyYW1lKHJlc3VsdHMob2JqZWN0ID0gbXBfZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJEaWFnbm9zaXMiLCAiQ09WSURfMTkiLCAiSGVhbHRoeV9Db250cm9sIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQpKQoKY292Ml92c19oY19yZXN1bHRzX2lkcyA9IGNvdjJfdnNfaGNfcmVzdWx0cyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUgfCAhZ3JlcGwoIkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKSAlPiUgCiAgYXJyYW5nZShsb2cyRm9sZENoYW5nZSkKCndyaXRlLmNzdihjb3YyX3ZzX2hjX3Jlc3VsdHNfaWRzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzE3X3N0YW5kYXJkX0RFQV9jb3ZpZF9vdmVyX2hlYWx0aHljb250cm9scy5jc3YiKQoKY292Ml92c19oY19yZXN1bHRzX2lkcwpgYGAgICAKICAgClVwcmVndWxhdGlvbiBvZiBDb1YtMiBnZW5lcyBpcyBnb3JnZW91cwogICAKVmVyc3VzIG5vbi1wbmEgKHNpY2spIGNvbnRyb2xzCmBgYHtyfQpjb3YyX3ZzX25wY19yZXN1bHRzID0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKG9iamVjdCA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygiRGlhZ25vc2lzIiwgIkNPVklEXzE5IiwgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUKSkKCmNvdjJfdnNfbnBjX3Jlc3VsdHNfaWRzID0gY292Ml92c19ucGNfcmVzdWx0cyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUgfCAhZ3JlcGwoIkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKSAlPiUgCiAgYXJyYW5nZShsb2cyRm9sZENoYW5nZSkKCndyaXRlLmNzdihjb3YyX3ZzX25wY19yZXN1bHRzX2lkcywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcxN19zdGFuZGFyZF9ERUFfY292aWRfb3Zlcl9ub25wbmV1bW9uaWFjb250cm9scy5jc3YiKQoKY292Ml92c19ucGNfcmVzdWx0c19pZHMKYGBgCiAgIApWZXJzdXMgb3RoZXIgdmlyYWwgUE5BCmBgYHtyfQpjb3YyX3ZzX292cF9yZXN1bHRzID0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKG9iamVjdCA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygiRGlhZ25vc2lzIiwgIkNPVklEXzE5IiwgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUKSkKCmNvdjJfdnNfb3ZwX3Jlc3VsdHNfaWRzID0gY292Ml92c19vdnBfcmVzdWx0cyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUgfCAhZ3JlcGwoIkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKSAlPiUgCiAgYXJyYW5nZShsb2cyRm9sZENoYW5nZSkKCmNvdjJfdnNfb3ZwX3Jlc3VsdHNfaWRzCgp3cml0ZS5jc3YoY292Ml92c19vdnBfcmVzdWx0c19pZHMsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MTdfc3RhbmRhcmRfREVBX2NvdmlkX292ZXJfb3RoZXJ2aXJhbHBuZXVtb25pYS5jc3YiKQpgYGAgICAKICAgClZlcnN1cyBvdGhlciBQTkEKYGBge3J9CmNvdjJfdnNfb3RoZXJfcG5hX3Jlc3VsdHMgPSBhcy5kYXRhLmZyYW1lKHJlc3VsdHMob2JqZWN0ID0gbXBfZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJEaWFnbm9zaXMiLCAiQ09WSURfMTkiLCAiT3RoZXJfUG5ldW1vbmlhIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQpKQoKY292Ml92c19vdGhlcl9wbmFfcmVzdWx0c19pZHMgPSBjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzICU+JSAKICByb3duYW1lc190b19jb2x1bW4oImVuc2VtYmxfZ2VuZV9pZCIpICU+JSAKICBsZWZ0X2pvaW4oLiwgZ2VuZV9jb252KSAlPiUgCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgMC4wNSB8ICFncmVwbCgiRU5TRyIsIGVuc2VtYmxfZ2VuZV9pZCkpICU+JSAKICBhcnJhbmdlKGxvZzJGb2xkQ2hhbmdlKQoKd3JpdGUuY3N2KGNvdjJfdnNfb3RoZXJfcG5hX3Jlc3VsdHNfaWRzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzE3X3N0YW5kYXJkX0RFQV9jb3ZpZF9vdmVyX290aGVycG5ldW1vbmlhLmNzdiIpCgpjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzX2lkcwpgYGAgIAogICAKIyMjIE1BIFBsb3QgICAKYGBge3IgZXZhbD1GQUxTRX0KcHJldHR5X01BX3Bsb3QoY292Ml92c19vdnBfcmVzdWx0cywgY3VzdG9tX2Fubm90YXRpb24gPSAgZ2VuZV9jb252KQpgYGAKCiAgIAojIyMgSGVhdG1hcCAgIAogICAKSG93IG1hbnkgY2x1c3RlcnMgZG9lcyBpdCB0YWtlPyAgIApgYGB7ciBldmFsPUZBTFNFfQplbGJvdyA9IGtfZWxib3coZGdlID0gbXBfZGVzLCBkZXNpZ24gPSAifkRpYWdub3NpcyIsIAogICAgICAgIGNvcmVzID0gMTIsIAogICAgICAgIG1pblJlcHMgPSBJbmYsCiAgICAgICAgcmFuZG9tX3NlZWQgPSAxMjM0NSwKICAgICAgICBtYXhfayA9IDI1LAogICAgICAgIHF2YWxfY3V0b2ZmID0gMC4wMSkKZWxib3cKYGBgICAgCjUgc2VlbXMgZmFpci4gICAKICAgIApgYGB7ciBldmFsPUZBTFNFfQppbnR1YmF0aW9uX3BhbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJQdXJwbGVzIilbMzo5XSkobWF4KG1wX2RlcyRmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIG5hLnJtID0gVCkgKyAxKQppbnR1YmF0aW9uX3BhbFsxOjNdID0gcmVwKCIjMDAwMDAwIiwzKSAjaGlnaGxpZ2h0ICJEMCIKCmNvdjJfa21lYW5zX25vY2x1c3RlcmluZyA9IGtfbWVhbnNfZmlndXJlKGRnZSA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5EaWFnbm9zaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fYW5ub3RhdGlvbnMgPSAib3JnLkhzLmVnLmRiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9kYiA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZmFjdG9ycyA9IGMoIkRpYWdub3NpcyIsICJmaW5pdGVfZGF5X29mX2ludHViYXRpb24iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0yLCAyLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluUmVwcyA9IEluZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ2VuZXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlfZ29fdGVybXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nb190ZXJtcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlTWVhbkN1dG9mZiA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbV9zZWVkID0gMTIzNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXZhbF9jdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gbGlzdChEaWFnbm9zaXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSBmaWcyX3BhbFsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gZmlnMl9wYWxbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gZmlnMl9wYWxbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiA9ICBpbnR1YmF0aW9uX3BhbCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9vcmRlciA9IGMoMywgNSwgMSwgMiwgNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvcnRDb2x1bW5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fc29ydF9mYWN0b3JzID0gYygiRGlhZ25vc2lzIiwgImZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiIpKQoKY292Ml9rbWVhbnNfY2x1c3RlcmVkID0ga19tZWFuc19maWd1cmUoZGdlID0gbXBfZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSAifkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9mYWN0b3JzID0gYygiRGlhZ25vc2lzIiwgImZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTIsIDIsIGxlbmd0aC5vdXQ9MTAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5SZXBzID0gSW5mLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nZW5lcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheV9nb190ZXJtcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuX2dvX3Rlcm1zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VNZWFuQ3V0b2ZmID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tX3NlZWQgPSAxMjM0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdmFsX2N1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBsaXN0KERpYWdub3NpcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSBmaWcyX3BhbFsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzRdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uID0gIGludHViYXRpb25fcGFsKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX29yZGVyID0gYygzLCA1LCAxLCAyLCA0KSkKZm9yKGkgaW4gMTpsZW5ndGgoY292Ml9rbWVhbnNfY2x1c3RlcmVkJEdPKSkKewogIGNvdjJfa21lYW5zX2NsdXN0ZXJlZCRHT1tbaV1dJGNsdXN0ZXIgPSBpCn0KY292Ml9rbWVhbnNfY2x1c3RlcmVkJGdvX2RmID0gYmluZF9yb3dzKGNvdjJfa21lYW5zX2NsdXN0ZXJlZCRHTykgJT4lIAogIGFycmFuZ2UoY2x1c3RlciwgcGFkaikKY292Ml9rbWVhbnNfY2x1c3RlcmVkJGV4cHJlc3Npb24gPSBjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gVCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgZHBseXI6OmZpbHRlcihlbnNlbWJsX2dlbmVfaWQgJWluJSBjb3YyX2ttZWFuc19jbHVzdGVyZWQkZ2VuZXMkZ2VuZSkgJT4lIAogIHJpZ2h0X2pvaW4oZ2VuZV9jb252LCAuKQpzYXZlUkRTKGNvdjJfa21lYW5zX2NsdXN0ZXJlZCwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDgwMl9rX21lYW5zX2NsdXN0ZXJlZC5yZHMiKQpzYXZlUkRTKGNvdjJfa21lYW5zX25vY2x1c3RlcmluZywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9rX21lYW5zX3VuY2x1c3RlcmVkLnJkcyIpCndyaXRlLmNzdihjb3YyX2ttZWFuc19jbHVzdGVyZWQkZ2VuZXMsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MjFfa19tZWFuc19nZW5lcy5jc3YiKQp3cml0ZS5jc3YoY292Ml9rbWVhbnNfY2x1c3RlcmVkJGdvX2RmLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX2tfbWVhbnNfR08uY3N2IikKYGBgICAgCiAgIApUaGlzIGlzIGFjdHVhbGx5IHZlcnkgY29vbCAoYW5kIG5pY2VseSBmb3Jlc2hhZG93cyB0aGUgbGF0ZXIgV0dDTkEgcmVzdWx0cykuIEMxOiBtb3N0bHkgQ09WSUQtcmVsYXRlZCghKTsgaGlnaGx5IGVucmljaGVkIGZvciB0eXBlIEkgaW50ZXJmZXJvbiByZXNwb25zZSAobm90IHByb2R1Y3Rpb24gc28gbXVjaCksIGFzIHdlbGwgYXMgTUhDLUkuIEMyOiBtb3N0bHkgbm9udmlyYWwgcG5ldW1vbmlhcy4gUHJldHR5IGNsYXNzaWMgU1RBVDMgaW5mbGFtbWF0b3J5IHJlc3BvbnNlLiAKICAgCiMjIyBEMCBIZWF0bWFwICAgCmBgYHtyIGV2YWw9RkFMU0V9CmQwX2RlcyA9IG1wX2Rlc1ssICFpcy5uYShtcF9kZXMkZGF5X29mX2ludHViYXRpb24pICYgbXBfZGVzJGRheV9vZl9pbnR1YmF0aW9uIDw9IDIgJiBtcF9kZXMkZGF5X29mX2ludHViYXRpb24gPj0gMF0KIyBjb3YyX2QwX2ttZWFuc19ub2NsdXN0ZXJpbmcgPSBrX21lYW5zX2ZpZ3VyZShkZ2UgPSBkMF9kZXMsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9ICJ+RGlhZ25vc2lzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMywKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuc2VtYmxfZGIgPSAiaHNhcGllbnNfZ2VuZV9lbnNlbWJsIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZmFjdG9ycyA9IGMoIkRpYWdub3NpcyIsICJwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2giKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTMsIDMsIGxlbmd0aC5vdXQ9MTAxKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IDEyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluUmVwcyA9IEluZiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nZW5lcyA9IFQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X2dvX3Rlcm1zID0gRiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nb190ZXJtcyA9IFQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfZm9udHNpemUgPSAyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tQW5ubyA9IGdlbmVfY29udiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9Kb2luQ29sID0gImVuc2VtYmxfZ2VuZV9pZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3J0Q29sdW1ucyA9IFQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xTb3J0RmFjdG9yID0gIkRpYWdub3NpcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlTWVhbkN1dG9mZiA9IDIwKQoKY292Ml9kMF9rbWVhbnNfY2x1c3RlcmVkID0ga19tZWFuc19maWd1cmUoZGdlID0gZDBfZGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5EaWFnbm9zaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fYW5ub3RhdGlvbnMgPSAib3JnLkhzLmVnLmRiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9kYiA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZmFjdG9ycyA9IGMoIkRpYWdub3NpcyIsICJwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2giKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluUmVwcyA9IEluZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ2VuZXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlfZ29fdGVybXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nb190ZXJtcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9mb250c2l6ZSA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tQW5ubyA9IGdlbmVfY29udiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vSm9pbkNvbCA9ICJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VNZWFuQ3V0b2ZmID0gMjApCmBgYAogICAKIyMgSW5kaXZpZHVhbCBnZW5lcyAgIAojIyMgQ0NMMjQgICAKVGhpcyB3YXMgYW4gaW50ZXJlc3RpbmcgQ09WSUQtc3BlY2lmaWMgaGl0LiBBY2NvcmRpbmcgdG8gcHVibGlzaGVkIGRhdGEsIGl0IGlzIGEgaGlnaGx5IHNlbGVjdGl2ZSBjaGVtb2F0dHJhY3RhbnQgZm9yIFQgY2VsbHMuIFdvdWxkIGV4cGVjdCB0aGF0IGl0IHNob3VsZCBjb3JyZWxhdGUgd2l0aCBUIGNlbGwgYWJ1bmRhbmNlLiAgIAogICAKYGBge3J9CmNjbDI0X2NvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDEwNjE3OCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSAiRGlhZ25vc2lzIiwKICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBwYyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQpCmdncGxvdChjY2wyNF9jb3VudHMsIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gY291bnQsIGZpbGwgID0gRGlhZ25vc2lzKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuMSwgd2lkdGggPSAwLjI1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklEXzE5IiA9IGZpZzJfcGFsWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9QbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gIkhlYWx0aHlcbkNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSAiTm9uLVBuZXVtb25pYVxuQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gIkNPVklELTE5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gIk90aGVyIFZpcmFsXG5QbmV1bW9uaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSAiT3RoZXJcblBuZXVtb25pYSIpKSArCiAgeGxhYigiIikgKwogIHlsYWIoIkNDTDI0IENvdW50cyIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgogICAKYGBge3J9CmNjbDI0X2NkNCA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDEwNjE3OCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSAicGVyY2VudF9DRDRfdG90YWwiLAogICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKQpjY2wyNF9jZDggPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMDYxNzgiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gInBlcmNlbnRfQ0Q4X3RvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwKICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKY2NsMjRfdGNlbGxzID0gbGVmdF9qb2luKGNjbDI0X2NkNCwgY2NsMjRfY2Q4KSAlPiUgCiAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZsb3dfcGFyYW1ldGVyIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwZXJjZW50IiwKICAgICAgICAgICAgICAgY29scyA9IGMocGVyY2VudF9DRDhfdG90YWwsIHBlcmNlbnRfQ0Q0X3RvdGFsKSkKCmdncGxvdChjY2wyNF90Y2VsbHMsIGFlcyh4ID0gY291bnQsIHkgPSBwZXJjZW50KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGZhY2V0X3dyYXAofmZsb3dfcGFyYW1ldGVyKSArCiAgc2NhbGVfeF9sb2cxMCgpCmBgYApQcmV0dHkgcG9vciBjb3JyZWxhdGlvbiAgIAogICAKIyMgSUwtNiAgIApgYGB7cn0KaWw2X2NvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDEzNjI0NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSAiRGlhZ25vc2lzIiwKICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBwYyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQpCmdncGxvdChpbDZfY291bnRzLCBhZXMoeCA9IERpYWdub3NpcywgeSA9IGNvdW50LCBmaWxsICA9IERpYWdub3NpcykpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjUsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKHNpemUgPSAwLjEsIHdpZHRoID0gMC4yNSkgKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiSGVhbHRoeV9Db250cm9sIiA9IGZpZzJfcGFsWzZdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSBmaWcyX3BhbFsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSBmaWcyX3BhbFsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gZmlnMl9wYWxbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzRdKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiSGVhbHRoeV9Db250cm9sIiA9ICJIZWFsdGh5XG5Db250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gIk5vbi1QbmV1bW9uaWFcbkNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklEXzE5IiA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9ICJPdGhlciBWaXJhbFxuUG5ldW1vbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9QbmV1bW9uaWEiID0gIk90aGVyXG5QbmV1bW9uaWEiKSkgKwogIHhsYWIoIiIpICsKICB5bGFiKCJJTC02IENvdW50cyIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgojIyBTYXNoYSdzIHBpY2tzICAgCiMjIyBBbGwgdG8gc3RhcnQgICAKYGBge3J9CnNhc2hhX2dlbmVzID0gYygiQ0NMMjAiLCAiQ0NMMjQiLCAiQ0NMMyIsICJDQ0w4IiwgIkNDUjIiLCAiQ0NMMiIsICJJTDFBIiwgIklMMUIiLCAiQVJFRyIsIAogICAgICAgICAgICAgICAgIkNYQ1I0IiwgIlRORlNGMTQiLCAiQ1hDTDMiLCAiQ1hDTDUiLCAiQ1hDTDEiLCAiQ1hDTDgiLCAiQVRGNCIsICJDRDE2NCIsIAogICAgICAgICAgICAgICAgIk1GR0U4IiwgIklMMTNSQTEiLCAiSUwxUkwxIiwgIklMMThSMSIsICJWU0lHNCIsICJWRUdGQSIsICJERElUNCIsICJCQUczIiwgCiAgICAgICAgICAgICAgICAiRE5BSkIxIiwgIkhTUDkwQUE2UCIsICJIU1BBMUIiLCAiSFNQQTFBIikKc2FzaGFfZ2VuZXMgPSBzdWJzZXQoZ2VuZV9jb252LCBnZW5lX25hbWUgJWluJSBzYXNoYV9nZW5lcykKCnNhc2hhX2NvdW50cyA9IG1jbGFwcGx5KHNhc2hhX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwgZnVuY3Rpb24oeCl7CiAgY291bnRzID0gcGxvdENvdW50cyhtcF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICBnZW5lID0geCwKICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gIkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCwKICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgICAgICAgICAgICAgcGMgPSBUKQogIGNvdW50cyRnZW5lID0geAogIHJldHVybihjb3VudHMpfSkKc2FzaGFfY291bnRzID0gYmluZF9yb3dzKHNhc2hhX2NvdW50cykgJT4lIAogIGxlZnRfam9pbiguLCBzYXNoYV9nZW5lcywgYnkgPSBjKCJnZW5lIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkKCnNhc2hhX2dlbmVfcGxvdCA9IGdncGxvdChzYXNoYV9jb3VudHMsIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gY291bnQsIGZpbGwgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC4xLCB3aWR0aCA9IDAuMjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSkpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSAiSGVhbHRoeVxuQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9ICJOb24tUG5ldW1vbmlhXG5Db250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSAiT3RoZXIgVmlyYWxcblBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9ICJPdGhlclxuUG5ldW1vbmlhIikpICsKICB4bGFiKCIiKSArCiAgeWxhYigiR2VuZSBDb3VudHMiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCh+Z2VuZV9uYW1lKQpzYXNoYV9nZW5lX3Bsb3QKYGBgICAgCgogICAKIyMgQ2x1c3RlcmluZyAgIAojIyMgQWxsIHNhbXBsZXMgICAKYGBge3J9CmRldGVjdGlvbl9yYXRlID0gZnVuY3Rpb24oeCkKewogIHJldHVybihzdW0oeCA+IDApIC8gbGVuZ3RoKHgpKSAKfQoKYWxsX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKQojZ2V0IDUwMCBtb3N0IHZhcmlhYmxlIGdlbmVzIHdpdGggPiAxMCUgZGV0ZWN0aW9uCnJ2ID0gcm93VmFycyhhbGxfY291bnRzKQpwcm9wX2RldGVjdGVkID0gYXBwbHkoWCA9IGFsbF9jb3VudHMsIE1BUkdJTiA9IDEsIEZVTiA9IGRldGVjdGlvbl9yYXRlKQpzZWxlY3Rpb25fY3JpdGVyaWEgPSBkYXRhLmZyYW1lKHNhbXBsZSA9IHJvd25hbWVzKGFsbF9jb3VudHMpLCB2YXIgPSBydiwgcHJvcF9kZXRlY3RlZCA9IHByb3BfZGV0ZWN0ZWQpICU+JSAKICBmaWx0ZXIocHJvcF9kZXRlY3RlZCA+PSAwLjEgJiB2YXIgPiAwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhcikpCnRvcF9nZW5lcyA9IGFzLmNoYXJhY3RlcihzZWxlY3Rpb25fY3JpdGVyaWEkc2FtcGxlWzE6MTAwMF0pCnRvcF9hbGxfY291bnRzID0gYWxsX2NvdW50c1t0b3BfZ2VuZXMsIF0KCmFubm90YXRpb24gPSBjb2xEYXRhKG1wX2RlcykgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb3ZpZF9jb25maXJtZWQsIAogICAgICAgICAgICAgICAgc2Fyc19jb3YyX2RldGVjdGVkLAogICAgICAgICAgICAgICAgc2V4LAogICAgICAgICAgICAgICAgI2RheV9vZl9pbnR1YmF0aW9uLAogICAgICAgICAgICAgICAgaW5mZWN0aW9uX3R5cGUsCiAgICAgICAgICAgICAgICBwZXJjZW50X25ldXRyb3BoaWxzLAogICAgICAgICAgICAgICAgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKQpnZW5lX2Fubm90YXRpb24gPSBnZW5lX2NvbnYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXModG9wX2FsbF9jb3VudHMpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJlbnNlbWJsX2dlbmVfaWQiKQoKcGhlYXRtYXAodG9wX2FsbF9jb3VudHMsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFQsCiAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLAogICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb24sCiAgICAgICAgIGxhYmVsc19yb3cgPSBnZW5lX2Fubm90YXRpb24kZ2VuZV9uYW1lLAogICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVCwKICAgICAgICAgZm9udHNpemVfcm93ID0gMiwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSwKICAgICAgICAgYW5nbGVfY29sID0gNDUpCmBgYAoKIyMjIERheSAwICAgCmBgYHtyfQpkYXkwX3NhbXBsZXMgPSB3aGljaChtcCRkYXlfb2ZfaW50dWJhdGlvbiA8PSAyKQpkYXkwID0gbXBfZGVzWywgZGF5MF9zYW1wbGVzXQpkYXkwX2NvdW50cyA9IGNvdW50cyhkYXkwLCBub3JtYWxpemVkID0gVCkKCiNnZXQgMTAwMCBtb3N0IHZhcmlhYmxlIGdlbmVzCnJ2ID0gcm93VmFycyhkYXkwX2NvdW50cykKcHJvcF9kZXRlY3RlZCA9IGFwcGx5KFggPSBkYXkwX2NvdW50cywgTUFSR0lOID0gMSwgRlVOID0gZGV0ZWN0aW9uX3JhdGUpCnNlbGVjdGlvbl9jcml0ZXJpYSA9IGRhdGEuZnJhbWUoc2FtcGxlID0gcm93bmFtZXMoZGF5MF9jb3VudHMpLCB2YXIgPSBydiwgcHJvcF9kZXRlY3RlZCA9IHByb3BfZGV0ZWN0ZWQpICU+JSAKICBmaWx0ZXIocHJvcF9kZXRlY3RlZCA+PSAwLjEgJiB2YXIgPiAwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhcikpCnRvcF9nZW5lcyA9IGFzLmNoYXJhY3RlcihzZWxlY3Rpb25fY3JpdGVyaWEkc2FtcGxlWzE6MTAwMF0pCnRvcF9kYXkwX2NvdW50cyA9IGRheTBfY291bnRzW3RvcF9nZW5lcywgXQoKYW5ub3RhdGlvbiA9IGNvbERhdGEoZGF5MCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb3ZpZF9jb25maXJtZWQsIAogICAgICAgICAgICAgICAgc2Fyc19jb3YyX2RldGVjdGVkLAogICAgICAgICAgICAgICAgZ2VuZGVyLAogICAgICAgICAgICAgICAgaW5mZWN0aW9uX3R5cGUsCiAgICAgICAgICAgICAgICBwZXJjZW50X25ldXRyb3BoaWxzLAogICAgICAgICAgICAgICAgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKQpnZW5lX2Fubm90YXRpb24gPSBnZW5lX2NvbnYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXModG9wX2RheTBfY291bnRzKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiZW5zZW1ibF9nZW5lX2lkIikKCnBoZWF0bWFwKHRvcF9kYXkwX2NvdW50cywKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub3RhdGlvbiwKICAgICAgICAgbGFiZWxzX3JvdyA9IGdlbmVfYW5ub3RhdGlvbiRnZW5lX25hbWUsCiAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBULAogICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICAgZm9udHNpemVfcm93ID0gMiwKICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKSgxMDApLAogICAgICAgICBhbmdsZV9jb2wgPSA0NSkKYGBgCiAgIAojIyBDb21wYXJpbmcgZGlmZmVyZW50IHBhdGhvZ2VucyAgIAojIyMgSW5kaXZpZHVhbCBwYXRob2dlbnMgICAKYGBge3IgZXZhbD1GQUxTRX0KcGF0aG9nZW5fc2V0ID0gbXBfZGVzWywgIWlzLm5hKG1wJHBhdGhvZ2VuKV0KcGF0aG9nZW5fc2V0JHBhdGhvZ2VuID0gZmFjdG9yKGFzLmNoYXJhY3RlcihwYXRob2dlbl9zZXQkcGF0aG9nZW4pKSAjcmVmYWN0b3IKcGF0aG9nZW5fa21lYW5zID0ga19tZWFuc19maWd1cmUoZGdlID0gcGF0aG9nZW5fc2V0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5wYXRob2dlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSA2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9mYWN0b3JzID0gYygicGF0aG9nZW4iLCAiY292aWRfY29uZmlybWVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IDEyKQpgYGAKUHJvYmFibHkgdG9vIGdyYW51bGFyICAgCiAgIAojIyMgQnJvYWQgZ3JvdXBpbmdzICAKYGBge3IgZXZhbD1GQUxTRX0KaW5mZWN0aW9uX3R5cGVfa21lYW5zID0ga19tZWFuc19maWd1cmUoZGdlID0gcGF0aG9nZW5fc2V0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5pbmZlY3Rpb25fdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSA0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9mYWN0b3JzID0gYygicGF0aG9nZW4iLCAiaW5mZWN0aW9uX3R5cGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gMTIpCmBgYAoKIyBSYW5kb20gICAKIyMgQUNFMiBjb3VudHMgICAKYGBge3J9CmFjZTJfY291bnRzID0gcGxvdENvdW50cyhtcF9kZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMzAyMzQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gImNvdmlkX2NvbmZpcm1lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBjID0gRikKZ2dwbG90KGFjZTJfY291bnRzLCBhZXMoeCA9IGNvdW50KSkgKwogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiZG9kZ2VyYmx1ZTQiLCApICsKICB5bGFiKCJOdW1iZXIgb2YgU2FtcGxlcyIpICsKICB4bGFiKCJBQ0UyIENvdW50IikKYGBgICAgCiAgIAojIFRyYWplY3Rvcmllcz8gICAKIyMgQWxsIHNhbXBsZXMgICAKV2Ugd2lsbCB1c2UgUENBIGFzIGlzIHJlY29tbWVuZGVkIHRvIG1ha2UgY29tcHV0YXRpb24gZmVhc2libGUuICAgICAgCmBgYHtyfQojc2VsZWN0IGdlbmVzIHdpdGggPiAxMCUgZGV0ZWN0aW9uLCBtZWFuIGNvdW50cyA+IDUKYWxsX2NvdW50cyA9IHQoY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpKSAjbmVlZCBzaXplIG5vcm1hbGl6YXRpb24KcHJvcF9kZXRlY3RlZCA9IGFwcGx5KFggPSBhbGxfY291bnRzLCBNQVJHSU4gPSAyLCBGVU4gPSBkZXRlY3Rpb25fcmF0ZSkKYWxsX2NvdW50cyA9IGFsbF9jb3VudHNbLCBwcm9wX2RldGVjdGVkID4gMC4xXQptZWFuX2RldGVjdGlvbiA9IGNvbE1lYW5zKGFsbF9jb3VudHMpCmFsbF9jb3VudHMgPSBhbGxfY291bnRzWywgbWVhbl9kZXRlY3Rpb24gPj0gNV0KCmFsbF9wY2EgPSBwcmNvbXAoYWxsX2NvdW50cykKZnZpel9laWcoYWxsX3BjYSwgCiAgICAgICAgIGJhcmZpbGwgPSAiZG9kZ2VyYmx1ZTQiLCAKICAgICAgICAgeGxhYiA9ICJQcmluY2lwYWwgQ29tcG9uZW50IiwKICAgICAgICAgeWxhYiA9ICJQZXJjZW50IFZhcmlhbmNlIEV4cGxhaW5lZCIsIAogICAgICAgICBtYWluID0gIiIsCiAgICAgICAgIG5jcCA9IDUwLAogICAgICAgICBnZ3RoZW1lID0gdGhlbWVfYncoKSwKICAgICAgICAgYWRkbGFiZWxzID0gVCkgIzIwIHNob3VsZCBjYXB0dXJlIGFsbW9zdCBldmVyeXRoaW5nCgp0b3RhbF91bWFwID0gdW1hcChYID0gYWxsX2NvdW50cywgCiAgICAgICAgICAgICAgICAgIHBjYSA9IDIwLCAKICAgICAgICAgICAgICAgICAgcGNhX2NlbnRlciA9IFQsIAogICAgICAgICAgICAgICAgICBuX3RocmVhZHMgPSAxLCAKICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiWiIsIAogICAgICAgICAgICAgICAgICBtaW5fZGlzdCA9IDAuMikKcm93bmFtZXModG90YWxfdW1hcCkgPSByb3duYW1lcyhhbGxfY291bnRzKQpjb2xuYW1lcyh0b3RhbF91bWFwKSA9IGMoIlVNQVBfMSIsICJVTUFQXzIiKQp0b3RhbF91bWFwID0gYXMuZGF0YS5mcmFtZSh0b3RhbF91bWFwKQp0b3RhbF91bWFwJHNhbXBsZSA9IHJvd25hbWVzKHRvdGFsX3VtYXApCnRvdGFsX3VtYXAgPSBsZWZ0X2pvaW4odG90YWxfdW1hcCwgbWV0YWRhdGEsIGJ5ID0gInNhbXBsZSIpICU+JSAKICBhcnJhbmdlKHN0dWR5X2lkLCBkYXlfb2ZfaW50dWJhdGlvbikgIyBzbyB3ZSBjYW4gZHJhdyBwYXRocwoKZ2dwbG90KHRvdGFsX3VtYXAsIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvciA9IERpYWdub3NpcykpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfZWxsaXBzZSgpCgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNoYXBlID0gc3R1ZHlfaWQsIGNvbG9yID0gZGF5X29mX2ludHViYXRpb24pKSArCiAgZ2VvbV9wYXRoKGFycm93ID0gZ3JpZDo6YXJyb3coKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgZmFjZXRfd3JhcCh+IERpYWdub3NpcykKYGBgICAgClBhdGllbnRzIGFjdHVhbGx5IHNlcGFyYXRlIG91dCByZWFsbHkgd2VsbCBoZXJlLiBUaGlzIG1pZ2h0IGJlIHdvcnRoIGluY2x1ZGluZyBhcyBhIHN1cHBsZW1lbnQuIFdpdGggdGhhdCBzYWlkLCBwcm9iYWJseSBiZXR0ZXIgdG8ganVzdCB1c2UgQ09WSUQgcGF0aWVudHMgZm9yICJ0cmFqZWN0b3JpZXMiLiBJdCBsb29rcyBsaWtlIHRoZXJlIG1heSBiZSBzb21lIHN0cnVjdHVyZSB0byB0aGUgQ09WSUQgZGF0YS4gICAgICAKICAgCgojIyBPbmx5IENPVklEICAgCmBgYHtyfQojcmVtb3ZlIG5vbi1kZXRlY3RlZCBnZW5lcwojbm90ZSB0aGF0IFBDQSBzaG91bGQgb25seSB1c2UgZ2VuZXMgZGV0ZWN0ZWQgaW4gYWxsIHNhbXBsZXMgKDMwODEpCkNPVklEX2NvdW50cyA9IHQoY291bnRzKG1wX2Rlc1ssIG1wX2RlcyREaWFnbm9zaXMgPT0gIkNPVklEXzE5Il0sIG5vcm1hbGl6ZWQgPSBUKSkgI25lZWQgc2l6ZSBub3JtYWxpemF0aW9uCnByb3BfZGV0ZWN0ZWQgPSBhcHBseShYID0gQ09WSURfY291bnRzLCBNQVJHSU4gPSAyLCBGVU4gPSBkZXRlY3Rpb25fcmF0ZSkKQ09WSURfY291bnRzID0gQ09WSURfY291bnRzWywgcHJvcF9kZXRlY3RlZCA+IDAuMV0KbWVhbl9kZXRlY3Rpb24gPSBjb2xNZWFucyhDT1ZJRF9jb3VudHMpCkNPVklEX2NvdW50cyA9IENPVklEX2NvdW50c1ssIG1lYW5fZGV0ZWN0aW9uID49IDVdCgpDT1ZJRF9wY2EgPSBwcmNvbXAoQ09WSURfY291bnRzKQpmdml6X2VpZyhDT1ZJRF9wY2EsIAogICAgICAgICBiYXJmaWxsID0gImRvZGdlcmJsdWU0IiwgCiAgICAgICAgIHhsYWIgPSAiUHJpbmNpcGFsIENvbXBvbmVudCIsCiAgICAgICAgIHlsYWIgPSAiUGVyY2VudCBWYXJpYW5jZSBFeHBsYWluZWQiLCAKICAgICAgICAgbWFpbiA9ICIiLAogICAgICAgICBuY3AgPSA1MCwKICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX2J3KCksCiAgICAgICAgIGFkZGxhYmVscyA9IFQpICMyMCBzaG91bGQgY2FwdHVyZSBhbG1vc3QgZXZlcnl0aGluZwoKQ09WSURfdW1hcCA9IHVtYXAoWCA9IENPVklEX2NvdW50cywgCiAgICAgICAgICAgICAgICAgIHBjYSA9IDIwLCAKICAgICAgICAgICAgICAgICAgcGNhX2NlbnRlciA9IFQsIAogICAgICAgICAgICAgICAgICBuX3RocmVhZHMgPSAxLCAKICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiWiIsIAogICAgICAgICAgICAgICAgICBtaW5fZGlzdCA9IDAuNCkKcm93bmFtZXMoQ09WSURfdW1hcCkgPSByb3duYW1lcyhDT1ZJRF9jb3VudHMpCmNvbG5hbWVzKENPVklEX3VtYXApID0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCkNPVklEX3VtYXAgPSBhcy5kYXRhLmZyYW1lKENPVklEX3VtYXApCkNPVklEX3VtYXAkc2FtcGxlID0gcm93bmFtZXMoQ09WSURfdW1hcCkKQ09WSURfdW1hcCA9IGxlZnRfam9pbihDT1ZJRF91bWFwLCBtZXRhZGF0YSwgYnkgPSAic2FtcGxlIikgJT4lIAogIGFycmFuZ2Uoc3R1ZHlfaWQsIGRheV9vZl9pbnR1YmF0aW9uKSAjIHNvIHdlIGNhbiBkcmF3IHBhdGhzCgpnZ3Bsb3QoQ09WSURfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gZGF5X29mX2ludHViYXRpb24pKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICBnZW9tX3BvaW50KCkKZ2dwbG90KENPVklEX3VtYXAsIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBzaGFwZSA9IHN0dWR5X2lkLCBjb2xvciA9IGRheV9vZl9pbnR1YmF0aW9uKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgZ2VvbV9wYXRoKGFycm93ID0gZ3JpZDo6YXJyb3coKSkKYGBgICAgCk5vdCBzbyBtdWNoIHN0cnVjdHVyZSBpdCBzZWVtcy4gICAKCiMgV0dDTkEgICAKV2hhdCBnZW5lIG1vZHVsZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBjb3ZpZD8gV2hpY2ggY2hhbmdlIHN1YnN0YW50aWFsbHkgb3ZlciB0aW1lIG9uIHZlbnRpbGF0b3I/ICAgCiMjIFRoZXNob2xkaW5nCmBgYHtyfQojc2V0dXAKZW5hYmxlV0dDTkFUaHJlYWRzKG5UaHJlYWRzID0gMTIpCldHQ05BblRocmVhZHMoKQoKIyBDaG9vc2UgYSBzZXQgb2Ygc29mdC10aHJlc2hvbGRpbmcgcG93ZXJzCnBvd2VycyA9IGMoMToyMCkKCiMgQ2FsbCB0aGUgbmV0d29yayB0b3BvbG9neSBhbmFseXNpcyBmdW5jdGlvbnMKc2Z0ID0gcGlja1NvZnRUaHJlc2hvbGQoYWxsX2NvdW50cywgcG93ZXJWZWN0b3IgPSBwb3dlcnMsIHZlcmJvc2UgPSA1LCBuZXR3b3JrVHlwZSA9ICJzaWduZWQiKQoKIyBQbG90IHRoZSByZXN1bHRzOgpzaXplR3JXaW5kb3coOSwgNSkKcGFyKG1mcm93ID0gYygxLDIpKQpjZXgxID0gMC45CgojIFNjYWxlLWZyZWUgdG9wb2xvZ3kgZml0IGluZGV4IGFzIGEgZnVuY3Rpb24gb2YgdGhlIHNvZnQtdGhyZXNob2xkaW5nIHBvd2VyCnBsb3Qoc2Z0JGZpdEluZGljZXNbLDFdLCAKICAgICAtc2lnbihzZnQkZml0SW5kaWNlc1ssM10pKnNmdCRmaXRJbmRpY2VzWywyXSwKICAgICB4bGFiPSJTb2Z0IFRocmVzaG9sZCAocG93ZXIpIiwKICAgICB5bGFiPSJTY2FsZSBGcmVlIFRvcG9sb2d5IE1vZGVsIEZpdCxzaWduZWQgUl4yIiwKICAgICB0eXBlPSJuIiwKICAgICBtYWluID0gcGFzdGUoIlNjYWxlIGluZGVwZW5kZW5jZSIpKQp0ZXh0KHNmdCRmaXRJbmRpY2VzWywxXSwgCiAgICAgLXNpZ24oc2Z0JGZpdEluZGljZXNbLDNdKSpzZnQkZml0SW5kaWNlc1ssMl0sCiAgICAgbGFiZWxzPXBvd2VycywKICAgICBjZXg9Y2V4MSwKICAgICBjb2w9InJlZCIpCgojIHRoaXMgbGluZSBjb3JyZXNwb25kcyB0byB1c2luZyBhbiBSXjIgY3V0LW9mZiBvZiBoCmFibGluZShoPTAuOTAsY29sPSJyZWQiKQoKIyBNZWFuIGNvbm5lY3Rpdml0eSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBzb2Z0LXRocmVzaG9sZGluZyBwb3dlcgpwbG90KHNmdCRmaXRJbmRpY2VzWywxXSwgCiAgICAgc2Z0JGZpdEluZGljZXNbLDVdLAogICAgIHhsYWI9IlNvZnQgVGhyZXNob2xkIChwb3dlcikiLAogICAgIHlsYWI9Ik1lYW4gQ29ubmVjdGl2aXR5IiwgCiAgICAgdHlwZT0ibiIsCiAgICAgbWFpbiA9IHBhc3RlKCJNZWFuIGNvbm5lY3Rpdml0eSIpKQp0ZXh0KHNmdCRmaXRJbmRpY2VzWywxXSwgc2Z0JGZpdEluZGljZXNbLDVdLCBsYWJlbHM9cG93ZXJzLCBjZXg9Y2V4MSxjb2w9InJlZCIpCmBgYCAgIAo3IGxvb2tzIGxpa2UgdGhlIGludGVyc2VjdGlvbiBhZnRlciBhZGRpbmcgaGVhbHRoeSBjb250cm9scyAgIAogICAKIyMgQ28tZXhwcmVzc2lvbiBieSBzaW1pbGFyaXR5IGFuZCBhZGphY2VuY3kgICAKYGBge3J9CnNvZnRQb3dlciA9IDcKYWRqYWNlbmN5ID0gYWRqYWNlbmN5KGFsbF9jb3VudHMsIHBvd2VyID0gc29mdFBvd2VyLCB0eXBlID0gInNpZ25lZCIpCmBgYAoKIyMgVG9wb2xvZ2ljYWwgb3ZlcmxhcCBtYXRyaXggICAKYGBge3J9CiMgVHVybiBhZGphY2VuY3kgaW50byB0b3BvbG9naWNhbCBvdmVybGFwClRPTSA9IFRPTXNpbWlsYXJpdHkoYWRqYWNlbmN5LCBUT01UeXBlID0gInNpZ25lZCIpCmRpc3NUT00gPSAxLVRPTQpgYGAKCiMjIENsdXN0ZXIgYnkgVE9NIGRpc3RhbmNlICAgCmBgYHtyfQpnZW5lVHJlZSA9IGhjbHVzdChhcy5kaXN0KGRpc3NUT00pLCBtZXRob2QgPSAiYXZlcmFnZSIpCgpzaXplR3JXaW5kb3coMTIsOSkKcGxvdChnZW5lVHJlZSwgCiAgICAgeGxhYj0iIiwgCiAgICAgc3ViPSIiLCAKICAgICBtYWluID0gIkdlbmUgY2x1c3RlcmluZyBvbiBUT00tYmFzZWQgZGlzc2ltaWxhcml0eSIsCiAgICAgbGFiZWxzID0gRkFMU0UsIAogICAgIGhhbmcgPSAwLjA0KQpgYGAgICAKICAgCiMjIENyZWF0ZSBtb2R1bGVzICAgCmBgYHtyfQptaW5Nb2R1bGVTaXplID0gMzAgIyBtYXkgbmVlZCB0byBhZGp1c3QKCiMgTWFrZSBtb2R1bGVzIGJhc2VkIG9uIGNsdXN0ZXJzCmR5bmFtaWNNb2RzID0gY3V0cmVlRHluYW1pYyhkZW5kcm8gPSBnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0TSA9IGRpc3NUT00sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWVwU3BsaXQgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFtUmVzcGVjdHNEZW5kcm8gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbkNsdXN0ZXJTaXplID0gbWluTW9kdWxlU2l6ZSkKdGFibGUoZHluYW1pY01vZHMpCmBgYCAgIAogICAKIyMjIExhYmVsIG1vZHVsZXMgKHllYWggdGhpcyBpcyBkdW1iIC0tIHJlbmFtZSBsYXRlcikgICAKYGBge3J9CiMgQ29udmVydCBudW1lcmljIGxhYmVscyBpbnRvIGNvbG9ycwpkeW5hbWljQ29sb3JzID0gbGFiZWxzMmNvbG9ycyhkeW5hbWljTW9kcykKdGFibGUoZHluYW1pY0NvbG9ycykKCiMgUGxvdCB0aGUgZGVuZHJvZ3JhbSBhbmQgY29sb3JzIHVuZGVybmVhdGgKc2l6ZUdyV2luZG93KDgsNikKcGxvdERlbmRyb0FuZENvbG9ycyhnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgZHluYW1pY0NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIkR5bmFtaWMgVHJlZSBDdXQiLAogICAgICAgICAgICAgICAgICAgIGRlbmRyb0xhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgIGhhbmcgPSAwLjAzLAogICAgICAgICAgICAgICAgICAgIGFkZEd1aWRlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICBndWlkZUhhbmcgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgIG1haW4gPSAiR2VuZSBkZW5kcm9ncmFtIGFuZCBtb2R1bGUgY29sb3JzIikKYGBgICAgCkxvb2tzIGxpa2Ugd2UgY2FwdHVyZWQgdGhlIHN0cnVjdHVyZSBwcmV0dHkgd2VsbC4gICAgICAKICAgCiMjIyBNZXJnZSBzaW1pbGFyIG1vZHVsZXMgICAKYGBge3J9CiMgQ2FsY3VsYXRlIGVpZ2VuZ2VuZXMKTUVMaXN0ID0gbW9kdWxlRWlnZW5nZW5lcyhhbGxfY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSBkeW5hbWljQ29sb3JzKQpNRXMgPSBNRUxpc3QkZWlnZW5nZW5lcwoKIyBDYWxjdWxhdGUgZGlzc2ltaWxhcml0eSBvZiBtb2R1bGUgZWlnZW5nZW5lcwpNRURpc3MgPSAxLWNvcihNRXMpCgojIENsdXN0ZXIgbW9kdWxlIGVpZ2VuZ2VuZXMKTUVUcmVlID0gaGNsdXN0KGFzLmRpc3QoTUVEaXNzKSwgCiAgICAgICAgICAgICAgICBtZXRob2QgPSAiYXZlcmFnZSIpCgojIFBsb3QgdGhlIHJlc3VsdApzaXplR3JXaW5kb3coNywgNikKcGxvdChNRVRyZWUsIAogICAgIG1haW4gPSAiQ2x1c3RlcmluZyBvZiBtb2R1bGUgZWlnZW5nZW5lcyIsCiAgICAgeGxhYiA9ICIiLAogICAgIHN1YiA9ICIiKQoKI05vdyBjdXQgYXQgaGVpZ2h0IG9mIDAuNSB0byBnZXQgY29ycmVsYXRpb24gb2YgMC41ICAKI3N0YW5kYXJkIGlzIDAuMjUsIGJ1dCB3ZSBoYXZlIHNvbWUgcmVhbGx5IHNpbWlsYXIgbW9kdWxlcyB0aGF0IGFyZSBub3QgcmVsZXZhbnQKTUVEaXNzVGhyZXMgPSAwLjI1CgojIFBsb3QgdGhlIGN1dCBsaW5lIGludG8gdGhlIGRlbmRyb2dyYW0KYWJsaW5lKGg9TUVEaXNzVGhyZXMsIAogICAgICAgY29sID0gInJlZCIpCgojIENhbGwgYW4gYXV0b21hdGljIG1lcmdpbmcgZnVuY3Rpb24KbWVyZ2UgPSBtZXJnZUNsb3NlTW9kdWxlcyhhbGxfY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkeW5hbWljQ29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjdXRIZWlnaHQgPSBNRURpc3NUaHJlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IDMpCgojIFRoZSBtZXJnZWQgbW9kdWxlIGNvbG9ycwptZXJnZWRDb2xvcnMgPSBtZXJnZSRjb2xvcnMKCiMgRWlnZW5nZW5lcyBvZiB0aGUgbmV3IG1lcmdlZCBtb2R1bGVzOgptZXJnZWRNRXMgPSBtZXJnZSRuZXdNRXMKCiMgUmVuYW1lIHRvIG1vZHVsZUNvbG9ycwptb2R1bGVDb2xvcnMgPSBtZXJnZWRDb2xvcnMKCiMgQ29uc3RydWN0IG51bWVyaWNhbCBsYWJlbHMgY29ycmVzcG9uZGluZyB0byB0aGUgY29sb3JzCmNvbG9yT3JkZXIgPSBjKCJncmV5Iiwgc3RhbmRhcmRDb2xvcnMoNTApKQptb2R1bGVMYWJlbHMgPSBtYXRjaChtb2R1bGVDb2xvcnMsIGNvbG9yT3JkZXIpLTEKTUVzID0gbWVyZ2VkTUVzCgojcmVwbG90CnNpemVHcldpbmRvdygxMiwgOSkKcGxvdERlbmRyb0FuZENvbG9ycyhnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgY2JpbmQoZHluYW1pY0NvbG9ycywgbWVyZ2VkQ29sb3JzKSwKICAgICAgICAgICAgICAgICAgICBjKCJEeW5hbWljIFRyZWUgQ3V0IiwgIk1lcmdlZCBkeW5hbWljIiksCiAgICAgICAgICAgICAgICAgICAgZGVuZHJvTGFiZWxzID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgIGhhbmcgPSAwLjAzLAogICAgICAgICAgICAgICAgICAgIGFkZEd1aWRlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgZ3VpZGVIYW5nID0gMC4wNSkKYGBgICAgCk5vIGNoYW5nZSAgIAogICAKIyMgUmVsYXRlIGJhY2sgdG8gdHJhaXRzICAgCiMjIyBXaXRob3V0IHZlbnQgc2V0dGluZ3MgICAKYGBge3J9CiMgRGVmaW5lIG51bWJlcnMgb2YgZ2VuZXMgYW5kIHNhbXBsZXMKbkdlbmVzID0gbmNvbChhbGxfY291bnRzKQpuU2FtcGxlcyA9IG5yb3coYWxsX2NvdW50cykKbWV0YWRhdGEgPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEobXBfZGVzKSkKbWRfb2ZfaW50ZXJlc3QgPSBtZXRhZGF0YSAlPiUgCiAgbXV0YXRlKGRlY2Vhc2VkID0gaWZlbHNlKGJpbm5lZF9vdXRjb21lID09ICJEZWNlYXNlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaGFzX2NvdmlkID0gaWZlbHNlKGNvdmlkX2NvbmZpcm1lZCA9PSAiVFJVRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoY292Ml9kZXRlY3RlZCA9IGlmZWxzZShzYXJzX2NvdjJfZGV0ZWN0ZWQgPT0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaGFzX3BuZXVtb25pYSA9IGlmZWxzZShwbmFfdHlwZSA9PSAiTm9uLVBuZXVtb25pYSBDb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAxKSkgJT4lIAogIG11dGF0ZShjb2luZmVjdGlvbl9kZXRlY3RlZCA9IGlmZWxzZShhbnlfbm9udmlyYWwgPT0gIlRSVUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKG90aGVyX3ZpcmFsX3BuYSA9IGlmZWxzZShwbmFfdHlwZSA9PSAiT3RoZXIgVmlyYWwgUG5ldW1vbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShub252aXJhbF9wbmEgPSBpZmVsc2UocG5hX3R5cGUgPT0gIk90aGVyIFBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaXNfaGVhbHRoeV9jb250cm9sID0gaWZlbHNlKHBuYV90eXBlID09ICJIZWFsdGh5IENvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgZHBseXI6OnNlbGVjdChkZWNlYXNlZCwgaGFzX2NvdmlkLCBjb3YyX2RldGVjdGVkLCBoYXNfcG5ldW1vbmlhLAogICAgICAgICAgICAgICAgb3RoZXJfdmlyYWxfcG5hLCBub252aXJhbF9wbmEsIGlzX2hlYWx0aHlfY29udHJvbCwKICAgICAgICAgICAgICAgIHBlcmNlbnRfbmV1dHJvcGhpbHMsIHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCwKICAgICAgICAgICAgICAgIHBlcmNlbnRfQ0Q0X3RvdGFsLCBwZXJjZW50X0NEOF90b3RhbCwgZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uLAogICAgICAgICAgICAgICAgQ19SZWFjdGl2ZV9Qcm90ZWluLCBEX0RJTUVSLCBQUk9DQUxDSVRPTklOLCBtZWFuX2FwcykKIyBSZWNhbGN1bGF0ZSBNRXMgd2l0aCBjb2xvciBsYWJlbHMKTUVzMCA9IG1vZHVsZUVpZ2VuZ2VuZXMoYWxsX2NvdW50cywgbW9kdWxlQ29sb3JzKSRlaWdlbmdlbmVzCk1FcyA9IG9yZGVyTUVzKE1FczApCm1vZHVsZVRyYWl0Q29yID0gYmljb3IoTUVzLCAKICAgICAgICAgICAgICAgICAgICAgbWRfb2ZfaW50ZXJlc3QsIAogICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwKICAgICAgICAgICAgICAgICAgICAgbWF4UE91dGxpZXJzID0gMC4wNSkKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5TYW1wbGVzKSAlPiUgCiAgYXMubnVtZXJpYygpICU+JSAKICBwLmFkanVzdCguLCBtZXRob2QgPSAiZmRyIikgJT4lIAogIG1hdHJpeChuY29sID0gbmNvbChtb2R1bGVUcmFpdENvcikpCmNvbG5hbWVzKG1vZHVsZVRyYWl0UHZhbHVlKSA9IGNvbG5hbWVzKG1vZHVsZVRyYWl0Q29yKQpyb3duYW1lcyhtb2R1bGVUcmFpdFB2YWx1ZSkgPSByb3duYW1lcyhtb2R1bGVUcmFpdENvcikKbW9kdWxlVHJhaXRDb3JfaG0gPSB0KG1vZHVsZVRyYWl0Q29yKQojanVzdCBtYWtlIHNpZ25pZmljYW50IG9yIG5vdApwdmFsc19obSA9IHQobW9kdWxlVHJhaXRQdmFsdWUpICU+JSAKICBhcy5tYXRyaXgoKQpwdmFsc19obVtwdmFsc19obSA8IDAuMDVdID0gIiIKcHZhbHNfaG1bcHZhbHNfaG0gIT0gIiJdID0gIk5TIgoKbGFicyA9IGMoIkRlY2Vhc2VkIiwgIkNPVklELTE5IiwgIlNBUlMtQ29WLTIgRGV0ZWN0ZWQiLCAiQW55IFBuZXVtb25pYSIsICJPdGhlciBWaXJhbCBQbmV1bW9uaWEiLCAiT3RoZXIgUG5ldW1vbmlhIiwKICAgICAgICAgIkhlYWx0aHkgQ29udHJvbCIsICIlIE5ldXRyb3BoaWxzIiwgIiUgTWFjcm9waGFnZXMgQ0QyMDYtaGlnaCIsICIlIENENCBUIiwgIiUgQ0Q4IFQiLAogICAgICAgICAiRGF5IG9mIEludHViYXRpb24iLCAiQ1JQIiwgIkQtRGltZXIiLCAiUHJvY2FsY2l0b25pbiIsICJNZWFuIEFQUyIpCm1vZHVsZV9jb3JfaGVhdG1hcCA9IHBoZWF0bWFwKG1hdCA9IG1vZHVsZVRyYWl0Q29yX2htLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfcm93ID0gbGFicywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2NvbCA9IHBhc3RlKCJNb2R1bGUiLCBjKDE6bmNvbChNRXMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlfbnVtYmVycyA9IHB2YWxzX2htLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSA3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGVfY29sID0gMzE1KQptb2R1bGVfY29yX2hlYXRtYXAgPSBwaGVhdG1hcChtYXQgPSBtb2R1bGVUcmFpdENvcl9obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdyA9IGxhYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19jb2wgPSBwYXN0ZSgiTW9kdWxlIiwgYygxOm5jb2woTUVzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBwdmFsc19obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJkQnUiKSkpKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlX2NvbCA9IDMxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMzIpCmBgYApNb2R1bGUgMTIgKHR1cnF1b2lzZSkgbG9va3MgbGlrZSB0aGUga2V5IE1vQU0gY2x1c3RlciwgNCAoYmx1ZSkgaXMga2V5IFRSQU0sIGFuZCBtb2R1bGUgMTQgKHB1cnBsZSkgaXMgbGlrZWx5IG91ciBJRk4gY2x1c3Rlci4KCiMjIyBXaXRoIHZlbnQgc2V0dGluZ3MgICAKYGBge3J9CiMgRGVmaW5lIG51bWJlcnMgb2YgZ2VuZXMgYW5kIHNhbXBsZXMKbkdlbmVzID0gbmNvbChhbGxfY291bnRzKQpuU2FtcGxlcyA9IG5yb3coYWxsX2NvdW50cykKCm1kX29mX2ludGVyZXN0ID0gbWV0YWRhdGEgJT4lIAogIG11dGF0ZShkZWNlYXNlZCA9IGlmZWxzZShiaW5uZWRfb3V0Y29tZSA9PSAiRGVjZWFzZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKGhhc19jb3ZpZCA9IGlmZWxzZShjb3ZpZF9jb25maXJtZWQgPT0gIlRSVUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKGNvdjJfZGV0ZWN0ZWQgPSBpZmVsc2Uoc2Fyc19jb3YyX2RldGVjdGVkID09IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKGhhc19wbmV1bW9uaWEgPSBpZmVsc2UocG5hX3R5cGUgPT0gIk5vbi1QbmV1bW9uaWEgQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMSkpICU+JSAKICBtdXRhdGUoY29pbmZlY3Rpb25fZGV0ZWN0ZWQgPSBpZmVsc2UoYW55X25vbnZpcmFsID09ICJUUlVFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShvdGhlcl92aXJhbF9wbmEgPSBpZmVsc2UocG5hX3R5cGUgPT0gIk90aGVyIFZpcmFsIFBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUobm9udmlyYWxfcG5hID0gaWZlbHNlKHBuYV90eXBlID09ICJPdGhlciBQbmV1bW9uaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKGlzX2hlYWx0aHlfY29udHJvbCA9IGlmZWxzZShwbmFfdHlwZSA9PSAiSGVhbHRoeSBDb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoZGVjZWFzZWQsIGhhc19jb3ZpZCwgY292Ml9kZXRlY3RlZCwgaGFzX3BuZXVtb25pYSwKICAgICAgICAgICAgICAgIG90aGVyX3ZpcmFsX3BuYSwgbm9udmlyYWxfcG5hLCBpc19oZWFsdGh5X2NvbnRyb2wsCiAgICAgICAgICAgICAgICBwZXJjZW50X25ldXRyb3BoaWxzLCBwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gsCiAgICAgICAgICAgICAgICBwZXJjZW50X0NENF90b3RhbCwgcGVyY2VudF9DRDhfdG90YWwsIGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwKICAgICAgICAgICAgICAgIENfUmVhY3RpdmVfUHJvdGVpbiwgRF9ESU1FUiwgUFJPQ0FMQ0lUT05JTiwgbWVhbl9hcHMsCiAgICAgICAgICAgICAgICBTdGF0aWNfQ29tcGxpYW5jZSwgUEZfcmF0aW8pCgojIFJlY2FsY3VsYXRlIE1FcyB3aXRoIGNvbG9yIGxhYmVscwpNRXMwID0gbW9kdWxlRWlnZW5nZW5lcyhhbGxfY291bnRzLCBtb2R1bGVDb2xvcnMpJGVpZ2VuZ2VuZXMKTUVzID0gb3JkZXJNRXMoTUVzMCkKbW9kdWxlVHJhaXRDb3IgPSBiaWNvcihNRXMsIAogICAgICAgICAgICAgICAgICAgICBtZF9vZl9pbnRlcmVzdCwgCiAgICAgICAgICAgICAgICAgICAgIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLAogICAgICAgICAgICAgICAgICAgICBtYXhQT3V0bGllcnMgPSAwLjA1KQoKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5TYW1wbGVzKSAlPiUgCiAgYXMubnVtZXJpYygpICU+JSAKICBwLmFkanVzdCguLCBtZXRob2QgPSAiZmRyIikgJT4lIAogIG1hdHJpeChuY29sID0gbmNvbChtb2R1bGVUcmFpdENvcikpCmNvbG5hbWVzKG1vZHVsZVRyYWl0UHZhbHVlKSA9IGNvbG5hbWVzKG1vZHVsZVRyYWl0Q29yKQpyb3duYW1lcyhtb2R1bGVUcmFpdFB2YWx1ZSkgPSByb3duYW1lcyhtb2R1bGVUcmFpdENvcikKCm1vZHVsZVRyYWl0Q29yX2htID0gdChtb2R1bGVUcmFpdENvcikKI2p1c3QgbWFrZSBzaWduaWZpY2FudCBvciBub3QKcHZhbHNfaG0gPSB0KG1vZHVsZVRyYWl0UHZhbHVlKSAlPiUgCiAgYXMubWF0cml4KCkKcHZhbHNfaG1bcHZhbHNfaG0gPCAwLjA1XSA9ICIiCnB2YWxzX2htW3B2YWxzX2htICE9ICIiXSA9ICJOUyIKCgpsYWJzID0gYygiRGVjZWFzZWQiLCAiQ09WSUQtMTkiLCAiU0FSUy1Db1YtMiBEZXRlY3RlZCIsICJBbnkgUG5ldW1vbmlhIiwgIk90aGVyIFZpcmFsIFBuZXVtb25pYSIsICJPdGhlciBQbmV1bW9uaWEiLAogICAgICAgICAiSGVhbHRoeSBDb250cm9sIiwgIiUgTmV1dHJvcGhpbHMiLCAiJSBNYWNyb3BoYWdlcyBDRDIwNi1oaWdoIiwgIiUgQ0Q0IFQiLCAiJSBDRDggVCIsCiAgICAgICAgICJEYXkgb2YgSW50dWJhdGlvbiIsICJDUlAiLCAiRC1EaW1lciIsICJQcm9jYWxjaXRvbmluIiwgIk1lYW4gQVBTIiwKICAgICAgICAgIlN0YXRpYyBDb21wbGlhbmNlIiwgIlAvRiBSYXRpbyIpCm1vZHVsZV9jb3JfaGVhdG1hcF92ZW50X21pbmkgPSBwaGVhdG1hcChtYXQgPSBtb2R1bGVUcmFpdENvcl9obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdyA9IGxhYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19jb2wgPSBwYXN0ZSgiTW9kdWxlIiwgYygxOm5jb2woTUVzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBwdmFsc19obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJkQnUiKSkpKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlX2NvbCA9IDMxNSkKbW9kdWxlX2Nvcl9oZWF0bWFwX3ZlbnQgPSBwaGVhdG1hcChtYXQgPSBtb2R1bGVUcmFpdENvcl9obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdyA9IGxhYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19jb2wgPSBwYXN0ZSgiTW9kdWxlIiwgYygxOm5jb2woTUVzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBwdmFsc19obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJkQnUiKSkpKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlX2NvbCA9IDMxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMjQpCnNhdmVSRFMobW9kdWxlX2Nvcl9oZWF0bWFwX3ZlbnQsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA4MDNfV0dDTkFfY29yX2hlYXRtYXAucmRzIikKYGBgICAgCk1vZHVsZSAxMyAoc2FsbW9uKSBtYXkgYWxzbyBiZSBpbnRlcmVzdGluZy4gQ29ycmVsYXRlcyB3aXRoIENPVklELCBDUlAsIGx5bXBob2N5dGVzLCBhbmQgdmVudCBwYXJhbXMhICAgIAogICAKIyMjIFNhbml0eSBjaGVjazogYXJlIHRoZSBDRDIwNiBtb2R1bGVzIFRSQU0vTW9BTSBtYXJrZXJzPyAgIApgYGB7cn0KbW9kdWxlX2Fzc2lnbm1lbnRzID0gZGF0YS5mcmFtZShlbnNlbWJsX2dlbmVfaWQgPSBjb2xuYW1lcyhhbGxfY291bnRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGUgPSBmYWN0b3IobWVyZ2VkQ29sb3JzKSkgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpCndyaXRlLmNzdihtb2R1bGVfYXNzaWdubWVudHMsCiAgICAgICAgICAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX1dHQ05BX21vZHVsZV9hc3NpZ25tZW50cy5jc3YiKQoKY2QyMDZfY29ycmVsYXRlZCA9IHN1YnNldChtb2R1bGVfYXNzaWdubWVudHMsIG1vZHVsZSA9PSAiYmx1ZSIpCmNkMjA2X2FudGljb3JyZWxhdGVkID0gc3Vic2V0KG1vZHVsZV9hc3NpZ25tZW50cywgbW9kdWxlID09ICJ0dXJxdW9pc2UiKQpjZDIwNl9jb3JyZWxhdGVkCmNkMjA2X2FudGljb3JyZWxhdGVkCmBgYApQcmV0dHkgaWRlYWwsIHllYWggICAKICAgCiAgIAojIyMgQ09WSUQtYXNzb2NpYXRlZCAgIApQdXJwbGUgY29udGFpbnMgYWxsIG9mIHRoZSBDb1YtMiBnZW5lcyEgICAKYGBge3J9CmNvdmlkX2NvcnJlbGF0ZWRfY2QyMDZfdW5jb3JyZWxhdGVkID0gc3Vic2V0KG1vZHVsZV9hc3NpZ25tZW50cywgbW9kdWxlID09ICJwdXJwbGUiKQpjb3ZpZF9jb3JyZWxhdGVkX2NkMjA2X3VuY29ycmVsYXRlZAp3cml0ZS5jc3YoY292aWRfY29ycmVsYXRlZF9jZDIwNl91bmNvcnJlbGF0ZWQsCiAgICAgICAgICAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX3B1cnBsZV9tb2R1bGVfMTRfZ2VuZXMuY3N2IikKYGBgClByZXR0eSBjbGFzc2ljIGludGVyZmVyb24gcmVzcG9uc2UuIExvb2sgYXQgdGhlIEdPLiAgIAogICAKYGBge3J9CiNmcm9tIGtfbWVhbnNfZmlndXJlCmNvbXBsZXRlX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKQp1bml2ZXJzZSA9IHJvd25hbWVzKGNvbXBsZXRlX2NvdW50c1tyb3dTdW1zKGNvbXBsZXRlX2NvdW50cykgPiAwLCBdKQpmaXNoZXJUZXN0ID0gbmV3KCJjbGFzc2ljQ291bnQiLCB0ZXN0U3RhdGlzdGljID0gR09GaXNoZXJUZXN0LCBuYW1lID0gIkZpc2hlciB0ZXN0IikKCmNsdXN0ZXJfZ2VuZXMgPSBjb3ZpZF9jb3JyZWxhdGVkX2NkMjA2X3VuY29ycmVsYXRlZCRlbnNlbWJsX2dlbmVfaWQKc2VsZWN0aW9uID0gYXMubnVtZXJpYyh1bml2ZXJzZSAlaW4lIGNsdXN0ZXJfZ2VuZXMpCm5hbWVzKHNlbGVjdGlvbikgPSB1bml2ZXJzZQpnb19kYXRhID0gbmV3KCJ0b3BHT2RhdGEiLCAKICAgICAgICAgICAgICBvbnRvbG9neSA9ICJCUCIsIAogICAgICAgICAgICAgIGFsbEdlbmVzID0gc2VsZWN0aW9uLAogICAgICAgICAgICAgIGdlbmVTZWwgPSBmdW5jdGlvbih4KXsKICAgICAgICAgICAgICAgIHJldHVybih4ID09IDEpfSwKICAgICAgICAgICAgICBhbm5vdCA9IGFubkZVTi5vcmcsIAogICAgICAgICAgICAgIG1hcHBpbmcgPSAib3JnLkhzLmVnLmRiIiwgCiAgICAgICAgICAgICAgSUQgPSAiZW5zZW1ibCIpCiAgCiNydW4gRmlzaGVyIHRlc3QKdGVzdF9yZXN1bHRzID0gZ2V0U2lnR3JvdXBzKGdvX2RhdGEsIGZpc2hlclRlc3QpCm1vZHVsZTE0X3Njb3JlID0gYXMuZGF0YS5mcmFtZShzY29yZSh0ZXN0X3Jlc3VsdHMpKQpjb2xuYW1lcyhtb2R1bGUxNF9zY29yZSkgPSAicHZhbCIKbW9kdWxlMTRfc2NvcmUgPSByb3duYW1lc190b19jb2x1bW4obW9kdWxlMTRfc2NvcmUsIHZhciA9ICJnb19pZCIpCiAgCiNhZGp1c3QgcC12YWx1ZXMgYW5kIHRha2Ugc2lnbmlmaWNhbnQKbW9kdWxlMTRfc2NvcmUkcGFkaiA9IHAuYWRqdXN0KG1vZHVsZTE0X3Njb3JlJHB2YWwsIG1ldGhvZCA9ICJmZHIiKQptb2R1bGUxNF9zY29yZSA9IHN1YnNldChtb2R1bGUxNF9zY29yZSwgcGFkaiA8IDAuMDUpCm1vZHVsZTE0X3Njb3JlJGRlc2NyaXB0aW9uID0gTkEKZm9yKGkgaW4gMTpucm93KG1vZHVsZTE0X3Njb3JlKSkKewogIG1vZHVsZTE0X3Njb3JlJGRlc2NyaXB0aW9uW2ldID0gR09URVJNW1ttb2R1bGUxNF9zY29yZSRnb19pZFtpXV1dQFRlcm0KfQoKI2FkZCBkZXNjcmlwdGlvbnMKbW9kdWxlMTRfc2NvcmUkZnVsbF9nbyA9IHBhc3RlKG1vZHVsZTE0X3Njb3JlJGdvX2lkLCBtb2R1bGUxNF9zY29yZSRkZXNjcmlwdGlvbikKd3JpdGUuY3N2KG1vZHVsZTE0X3Njb3JlLAogICAgICAgICAgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9wdXJwbGVfbW9kdWxlXzE0X0dPLmNzdiIpCm1vZHVsZTE0X3Njb3JlCmBgYApQcmV0dHkgbXVjaCBhbGwgVHlwZSBJIGludGVyZmVyb24gcmVsYXRlZC4gTW9zdCBvZiB0aGUgcGFwZXIgaXMgaGVyZS4gICAKICAgCiMjIyBNb2R1bGUgMTMgICAKVGhpcyBtb2R1bGUgaGFzIElSRjEgYW5kIHRoZSBNSEMtSSBnZW5lcyAgIApgYGB7cn0KbW9kdWxlMTMgPSBzdWJzZXQobW9kdWxlX2Fzc2lnbm1lbnRzLCBtb2R1bGUgPT0gInNhbG1vbiIpCm1vZHVsZTEzCndyaXRlLmNzdihtb2R1bGUxMywKICAgICAgICAgICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MjFfc2FsbW9uX21vZHVsZV8xM19nZW5lcy5jc3YiKQpgYGAKICAgCmBgYHtyfQojZnJvbSBrX21lYW5zX2ZpZ3VyZQpjbHVzdGVyX2dlbmVzID0gbW9kdWxlMTMkZW5zZW1ibF9nZW5lX2lkCnNlbGVjdGlvbiA9IGFzLm51bWVyaWModW5pdmVyc2UgJWluJSBjbHVzdGVyX2dlbmVzKQpuYW1lcyhzZWxlY3Rpb24pID0gdW5pdmVyc2UKZ29fZGF0YSA9IG5ldygidG9wR09kYXRhIiwgCiAgICAgICAgICAgICAgb250b2xvZ3kgPSAiQlAiLCAKICAgICAgICAgICAgICBhbGxHZW5lcyA9IHNlbGVjdGlvbiwKICAgICAgICAgICAgICBnZW5lU2VsID0gZnVuY3Rpb24oeCl7CiAgICAgICAgICAgICAgICByZXR1cm4oeCA9PSAxKX0sCiAgICAgICAgICAgICAgYW5ub3QgPSBhbm5GVU4ub3JnLCAKICAgICAgICAgICAgICBtYXBwaW5nID0gIm9yZy5Icy5lZy5kYiIsIAogICAgICAgICAgICAgIElEID0gImVuc2VtYmwiKQogIAojcnVuIEZpc2hlciB0ZXN0CnRlc3RfcmVzdWx0cyA9IGdldFNpZ0dyb3Vwcyhnb19kYXRhLCBmaXNoZXJUZXN0KQptb2R1bGUxM19zY29yZSA9IGFzLmRhdGEuZnJhbWUoc2NvcmUodGVzdF9yZXN1bHRzKSkKY29sbmFtZXMobW9kdWxlMTNfc2NvcmUpID0gInB2YWwiCm1vZHVsZTEzX3Njb3JlID0gcm93bmFtZXNfdG9fY29sdW1uKG1vZHVsZTEzX3Njb3JlLCB2YXIgPSAiZ29faWQiKQogIAojYWRqdXN0IHAtdmFsdWVzIGFuZCB0YWtlIHNpZ25pZmljYW50Cm1vZHVsZTEzX3Njb3JlJHBhZGogPSBwLmFkanVzdChtb2R1bGUxM19zY29yZSRwdmFsLCBtZXRob2QgPSAiZmRyIikKbW9kdWxlMTNfc2NvcmUgPSBzdWJzZXQobW9kdWxlMTNfc2NvcmUsIHBhZGogPCAwLjA1KQojIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uID0gTkEKIyBmb3IoaSBpbiAxOm5yb3cobW9kdWxlMTNfc2NvcmUpKQojIHsKIyAgIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uW2ldID0gR09URVJNW1ttb2R1bGUxM19zY29yZSRnb19pZFtpXV1dQFRlcm0KIyB9CiMgCiMgI2FkZCBkZXNjcmlwdGlvbnMKIyBtb2R1bGUxM19zY29yZSRmdWxsX2dvID0gcGFzdGUobW9kdWxlMTNfc2NvcmUkZ29faWQsIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uKQojIHdyaXRlLmNzdihtb2R1bGUxM19zY29yZSwKIyAgICAgICAgICAgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9zYWxtb25fbW9kdWxlXzEzX0dPLmNzdiIpCiMgbW9kdWxlMTNfc2NvcmUKYGBgCk5vIHNpZ25pZmljYW50IGhpdHMuICAgCiAgIAojIyBQbG90IGludGVyZXN0aW5nIG1vZHVsZXMgICAKIyMjIFB1cnBsZSBtb2R1bGUgKDE0KSBhbmQgZGlhZ25vc2lzLCBvdXRjb21lICAgCmBgYHtyfQp0b3RhbF91bWFwID0gTUVMaXN0JGF2ZXJhZ2VFeHByICU+JSAKICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZSIpICU+JSAKICBsZWZ0X2pvaW4odG90YWxfdW1hcCwgLikKY292aWRfdW1hcCA9IHRvdGFsX3VtYXAgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY292aWRfY29uZmlybWVkID09IFRSVUUpCgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBBRXB1cnBsZSwgY29sb3IgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9wb2ludCgpCm1vZHVsZTE0X3VtYXAgPSBnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBBRXB1cnBsZSwgY29sb3IgPSBwbmFfdHlwZSwgc2hhcGUgPSBiaW5uZWRfb3V0Y29tZSkpICsKICBnZW9tX3BvaW50KCkgKwogICB0aGVtZV9idygpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24tUG5ldW1vbmlhIENvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSUQtMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIgVmlyYWwgUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFBuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiYmxhY2siKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJEZWNlYXNlZCIgPSAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaXNjaGFyZ2VkIiA9IDE5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklucGF0aWVudCBGYWNpbGl0eSIgPSAxOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIgPSAxOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9IDEpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMobmFtZSA9ICJNb2R1bGUgMTQgRXhwcmVzc2lvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICByYW5nZSA9IGMoMSwgMTApKSArCiAgeGxhYigiVU1BUCAxIikgKwogIHlsYWIoIlVNQVAgMiIpCm1vZHVsZTE0X3VtYXAgCmBgYCAgIAogICAKIyMjIENDTDI0ICAgICAgCmBgYHtyfQpjY2wyNF9jb3VudHMgPSByb3duYW1lc190b19jb2x1bW4oY2NsMjRfY291bnRzLCB2YXIgPSAic2FtcGxlIikKY2NsMjRfY291bnRzID0gY2NsMjRfY291bnRzWywgMToyXQpjb2xuYW1lcyhjY2wyNF9jb3VudHMpWzJdID0gIkNDTDI0Igp0b3RhbF91bWFwID0gbGVmdF9qb2luKHRvdGFsX3VtYXAsIGNjbDI0X2NvdW50cykKY2NsMjRfdW1hcCA9IGdncGxvdCh0b3RhbF91bWFwLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgc2l6ZSA9IENDTDI0LCBjb2xvciA9IHBuYV90eXBlLCBzaGFwZSA9IGJpbm5lZF9vdXRjb21lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gIkFyaWFsIikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24tUG5ldW1vbmlhIENvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSUQtMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIgVmlyYWwgUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFBuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiYmxhY2siKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJEZWNlYXNlZCIgPSAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaXNjaGFyZ2VkIiA9IDE5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklucGF0aWVudCBGYWNpbGl0eSIgPSAxOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIgPSAxOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9IDEpICsKc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiQ0NMMjQgQ291bnRzIiwgdHJhbnMgPSAibG9nMTAiLCByYW5nZSA9IGMoMSwgMTApKSArCiAgeGxhYigiVU1BUCAxIikgKwogIHlsYWIoIlVNQVAgMiIpCmNjbDI0X3VtYXAgCmBgYApUaGlzIGlzIHJlYWxseSBjb29sISBUaGlzIGlzb2xhdGVzIG1vc3QgdGhlIHRoZSBJRk4tbm9uLXJlc3BvbnNpdmUgQ09WSUQgcGF0aWVudHMuIE1heWJlIHRoaXMgZHJpdmVzIGhldGVyb2dlbmVpdHkgaW4gY2VsbHR5cGUgY29tcG9zaXRpb24gaW4gdGhlIGx1bmc/ICAgCiAgIApgYGB7cn0KdGNlbGxfdW1hcCA9IGdncGxvdCh0b3RhbF91bWFwLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgc2l6ZSA9IHBlcmNlbnRfQ0QzX3RvdGFsLCBjb2xvciA9IHBuYV90eXBlLCBzaGFwZSA9IGJpbm5lZF9vdXRjb21lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gIkFyaWFsIikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24tUG5ldW1vbmlhIENvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSUQtMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIgVmlyYWwgUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFBuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiYmxhY2siKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJEZWNlYXNlZCIgPSAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaXNjaGFyZ2VkIiA9IDE5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklucGF0aWVudCBGYWNpbGl0eSIgPSAxOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIgPSAxOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9IDEpICsKc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VudCBMeW1waG9jeXRlcyIsIHJhbmdlID0gYygxLCAxMCkpICsKICB4bGFiKCJVTUFQIDEiKSArCiAgeWxhYigiVU1BUCAyIikKCnRjZWxsX3VtYXAgCmBgYAoKCiAgIAojIyMgQnJvd24vdHVycXVvaXNlIG1vZHVsZXMgYW5kIGRheSBvZiBpbnR1YmF0aW9uIGluIENPVklEIHBhdGllbnRzICAgClRSQU0gY29udGVudCAgIApgYGB7cn0KZ2dwbG90KHRvdGFsX3VtYXAsIGFlcyh4ID0gZGF5X29mX2ludHViYXRpb24sIHkgPSBBRWJsdWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpCgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBkYXlfb2ZfaW50dWJhdGlvbiwgeSA9IEFFdHVycXVvaXNlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQpgYGAKTm90IG11Y2ggb2YgYSBjb3JyZWxhdGlvbi4uLm1heWJlIGEgZmxhdCBsaW5lLCBhcyBJIGd1ZXNzIHdvdWxkIGJlIGV4cGVjdGVkIHdpdGggbmVhci1jb25zdGFudCByZWNydWl0bWVudC4gCiAgIAojIyBFZmZlY3Qgb2YgT1JGOCBleHByZXNzaW9uICAgCiMjIyBJc29sYXRlIGNvdW50cyAgIApgYGB7cn0Kb3JmOCA9IGNvdjJfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkW3doaWNoKGNvdjJfZ2VuZXMkZ2VuZV9uYW1lID09ICJPUkY4IildCm9yZjhfY291bnRzID0gcGxvdENvdW50cyhtcF9kZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IG9yZjgsIAogICAgICAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSAicG5hX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwYyA9IFQpCm9yZjhfc2FtcGxlcyA9IHJvd25hbWVzKHN1YnNldChvcmY4X2NvdW50cywgY291bnQgPjApKQoKZ2dwbG90KG9yZjhfY291bnRzLCBhZXMoeCA9IHBuYV90eXBlLCB5ID0gY291bnQpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKGFlcyhjb2xvciA9IGNvdW50ID4gMCkpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIHlsYWIoIk9SRjggQ291bnRzIikgKwogIHhsYWIoIiIpIApgYGAgICAKICAgCk5vdCBhIHRvbiBvZiBkZXRlY3Rpb24gYnV0IHZlcnkgY2xlYW4uICAgCiAgIAojIyMgQXNzb2NpYXRpb24gd2l0aCBpbnRlcmZlcm9uIHJlc3BvbnNlcyAgIApgYGB7cn0KbXBfZGVzJG9yZjhfZGV0ZWN0ZWQgPSBtcF9kZXMkc2FtcGxlICVpbiUgb3JmOF9zYW1wbGVzCnRvdGFsX3VtYXAkb3JmOF9kZXRlY3RlZCA9IHRvdGFsX3VtYXAkc2FtcGxlICVpbiUgb3JmOF9zYW1wbGVzCmdncGxvdCh0b3RhbF91bWFwLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgc2l6ZSA9IEFFcHVycGxlLCBjb2xvciA9IERpYWdub3Npcywgc2hhcGUgPSBvcmY4X2RldGVjdGVkKSkgKwogIGdlb21fcG9pbnQoKQpgYGAgIApQcmV0dHkgY2xlYXIgc3BhdGlhbCBjb3JyZWxhdGlvbi4uLmJ1dCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uPyAgIAogICAKYGBge3J9CmdncGxvdCh0b3RhbF91bWFwLCBhZXMoeCA9IG9yZjhfZGV0ZWN0ZWQsIHkgPSBBRXB1cnBsZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbG9yID0gRGlhZ25vc2lzKSkKCmhpZ2hfY292MiA9IGNvbG5hbWVzKGNvdjJfY291bnRzKVtjb2xTdW1zKGNvdjJfY291bnRzKSA+IDUwXQp0b3RhbF91bWFwJGNvdjJfZGV0ZWN0ZWQgPSB0b3RhbF91bWFwJHNhbXBsZSAlaW4lIGhpZ2hfY292MgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBjb3YyX2RldGVjdGVkLCB5ID0gQUVwdXJwbGUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKGFlcyhjb2xvciA9IERpYWdub3NpcykpCmBgYApUaGlzIHJlYWxseSBqdXN0IGNvcnJlbGF0ZXMgd2l0aCBvdmVyYWxsIHZpcmFsIGxvYWQgKHdoaWNoIGNvcnJlbGF0ZXMsIGluIHR1cm4sIHdpdGggT1JGOCBsZXZlbHMpLiBObyBzdXBwb3J0IHJlYWxseSBmb3IgdGhlIE9SRjggaW5oaWJpdGlvbiBvZiB0aGUgSUZOIHJlc3BvbnNlLCBhdCBsZWFzdCBhdCB0aGlzIHN0YWdlLiAgIAogICAKIyBJbnRlcmZlcm9uIHJlc3BvbnNlIG92ZXIgdGltZSAgIAojIyBXR0NOQSBNb2R1bGUgcHVycGxlICAgCiMjIyBBdmVyYWdlIGV4cHJlc3Npb24gICAKYGBge3J9Cm0xNF9jb3IgPSBjb3IudGVzdChjb3ZpZF91bWFwJEFFcHVycGxlLCBjb3ZpZF91bWFwJGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbikKbW9kdWxlXzE0X2NvcnBsb3QgPSBnZ3Bsb3QoY292aWRfdW1hcCwgYWVzKHggPSBmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIHkgPSBBRXB1cnBsZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAzMCwgeSA9IDIsIGxhYmVsID0gcGFzdGUwKCJSID0gIiwgcm91bmQobTE0X2NvciRlc3RpbWF0ZSwgZGlnaXRzID0gMikpLCBzaXplID0gNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gZmlnMl9wYWxbMl0pICsKICB0aGVtZV9idygpICsKICB4bGFiKCJEYXkgb2YgTWVjaGFuaWNhbCBWZW50aWxhdGlvbiIpICsKICB5bGFiKCJBdmVyYWdlIE1vZHVsZSAxNCBFeHByZXNzaW9uIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQptb2R1bGVfMTRfY29ycGxvdApgYGAKICAgCiMjIEdPIENhdGVnb3JpZXMgICAKIyMjIFB1bGwgZnJvbSBiaW9tYXJ0ICAgCmBgYHtyfQpodW1hbl9tYXJ0ID0gdXNlRW5zZW1ibCgiZW5zZW1ibCIsIGRhdGFzZXQgPSAiaHNhcGllbnNfZ2VuZV9lbnNlbWJsIiwgR1JDaCA9IDM3KQoKI25vdyBwdWxsIGRvd24gZ2VuZXMgYmFzZWQgb24gZ2VuZSBvbnRvbG9neSAoR08pIGRlZmluaXRpb25zCnR5cGVJX0lGTl9yZXNwb25zZSA9IGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiZXh0ZXJuYWxfZ2VuZV9uYW1lIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcnMgPSAiZ28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAiR086MDA2MDMzNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcnQgPSBodW1hbl9tYXJ0KQoKSUZOZ19yZXNwb25zZSA9IGdldEJNKGF0dHJpYnV0ZXMgPSBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiZXh0ZXJuYWxfZ2VuZV9uYW1lIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcnMgPSAiZ28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAiR086MDA2MDMzMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcnQgPSBodW1hbl9tYXJ0KQpgYGAgICAKICAgCiMjIyBBc3NpZ24gbWVhbiBleHByZXNzaW9uICAgCmBgYHtyfQp1bmZpbHRlcmVkX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKQp0eXBlSV9JRk5fcmVzcG9uc2UgPSBzdWJzZXQodHlwZUlfSUZOX3Jlc3BvbnNlLCBlbnNlbWJsX2dlbmVfaWQgJWluJSByb3duYW1lcyh1bmZpbHRlcmVkX2NvdW50cykpCklGTmdfcmVzcG9uc2UgPSBzdWJzZXQoSUZOZ19yZXNwb25zZSwgZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXModW5maWx0ZXJlZF9jb3VudHMpKQp0eXBlMV9jb3VudHMgPSB1bmZpbHRlcmVkX2NvdW50c1t0eXBlSV9JRk5fcmVzcG9uc2UkZW5zZW1ibF9nZW5lX2lkLCBtcF9kZXMkY292aWRfY29uZmlybWVkID09IFRSVUVdCnR5cGUxX2NvdW50cyA9IGFzLmRhdGEuZnJhbWUoY29sTWVhbnModHlwZTFfY291bnRzKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKY29sbmFtZXModHlwZTFfY291bnRzKVsyXSA9ICJ0eXBlSV9JRk5fcmVzcG9uc2UiCnR5cGUyX2NvdW50cyA9IHVuZmlsdGVyZWRfY291bnRzW0lGTmdfcmVzcG9uc2UkZW5zZW1ibF9nZW5lX2lkLCBtcF9kZXMkY292aWRfY29uZmlybWVkID09IFRSVUVdCnR5cGUyX2NvdW50cyA9IGFzLmRhdGEuZnJhbWUoY29sTWVhbnModHlwZTJfY291bnRzKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKY29sbmFtZXModHlwZTJfY291bnRzKVsyXSA9ICJJRk5nX3Jlc3BvbnNlIgppZm5fY291bnRzID0gdW5maWx0ZXJlZF9jb3VudHNbaW50ZXJzZWN0KElGTmdfcmVzcG9uc2UkZW5zZW1ibF9nZW5lX2lkLCB0eXBlSV9JRk5fcmVzcG9uc2UkZW5zZW1ibF9nZW5lX2lkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1wX2RlcyRjb3ZpZF9jb25maXJtZWQgPT0gVFJVRV0KaWZuX2NvdW50cyA9IGFzLmRhdGEuZnJhbWUoY29sTWVhbnMoaWZuX2NvdW50cykpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZSIpCmNvbG5hbWVzKGlmbl9jb3VudHMpWzJdID0gImdlbmVyYWxfSUZOX3Jlc3BvbnNlIgoKY292aWRfdW1hcCA9IGNvdmlkX3VtYXAgJT4lIAogIGxlZnRfam9pbiguLCB0eXBlMV9jb3VudHMpICU+JSAKICBsZWZ0X2pvaW4oLiwgdHlwZTJfY291bnRzKSAlPiUgCiAgbGVmdF9qb2luKC4sIGlmbl9jb3VudHMpCmBgYAogICAKIyMjIENvcnJlbGF0aW9ucyAgIApgYGB7cn0KdHlwZWlfY29yID0gY29yLnRlc3QoY292aWRfdW1hcCR0eXBlSV9JRk5fcmVzcG9uc2UsIGNvdmlkX3VtYXAkZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uKQp0eXBlaWlfY29yID0gY29yLnRlc3QoY292aWRfdW1hcCRJRk5nX3Jlc3BvbnNlLCBjb3ZpZF91bWFwJGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbikKZ2VuZXJhbF9jb3IgPSBjb3IudGVzdChjb3ZpZF91bWFwJGdlbmVyYWxfSUZOX3Jlc3BvbnNlLCBjb3ZpZF91bWFwJGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbikKYGBgCiAgIAojIyMgUGxvdCAgIApgYGB7cn0KI0dPOjAwNjAzMzcKdHlwZWlfY29ycGxvdCA9IGdncGxvdChjb3ZpZF91bWFwLCBhZXMoeCA9IGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwgeSA9IHR5cGVJX0lGTl9yZXNwb25zZSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9IGZpZzJfcGFsWzJdKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IDMwLCB5ID0gMTc1MCwgbGFiZWwgPSBwYXN0ZTAoIlIgPSAiLCByb3VuZCh0eXBlaV9jb3IkZXN0aW1hdGUsIGRpZ2l0cyA9IDIpKSwgc2l6ZSA9IDYpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIHlsYWIoIkF2ZXJhZ2UgVHlwZSBJIElGTiBQYXRod2F5IEdlbmUgRXhwcmVzc2lvbiIpICsKICB4bGFiKCJEYXkgb2YgTWVjaGFuaWNhbCBWZW50aWxhdGlvbiIpCnR5cGVpX2NvcnBsb3QgCgojR086MDA2MDMzMwp0eXBlaWlfY29ycGxvdCA9IGdncGxvdChjb3ZpZF91bWFwLCBhZXMoeCA9IGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwgeSA9IElGTmdfcmVzcG9uc2UpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSBmaWcyX3BhbFsyXSkgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAzMCwgeSA9IDMwMDAsIGxhYmVsID0gcGFzdGUwKCJSID0gIiwgcm91bmQodHlwZWlpX2NvciRlc3RpbWF0ZSwgZGlnaXRzID0gMikpLCBzaXplID0gNikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgeWxhYigiQXZlcmFnZSBJRk5nIFBhdGh3YXkgR2VuZSBFeHByZXNzaW9uIikgKwogIHhsYWIoIkRheSBvZiBNZWNoYW5pY2FsIFZlbnRpbGF0aW9uIikKdHlwZWlpX2NvcnBsb3QKCmdncGxvdChjb3ZpZF91bWFwLCBhZXMoeCA9IGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwgeSA9IGdlbmVyYWxfSUZOX3Jlc3BvbnNlKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gZmlnMl9wYWxbMl0pICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIHlsYWIoIkF2ZXJhZ2UgSUZOIHJlc3BvbnNlIEV4cHJlc3Npb24iKSArCiAgeGxhYigiRGF5IG9mIE1lY2hhbmljYWwgVmVudGlsYXRpb24iKQpgYGAgICAKCgogICAKIyBTZWNvbmQgYmF0Y2ggb2YgcGljbyBvcHRpbWl6YXRpb24gICAKTGV0J3MgZm9jdXMgb24gaW50ZXJmZXJvbi1oaSB2cyBpbnRlcmZlcm9uLWxvdyBzYW1wbGVzICAgCiMjIyBJZGVudGlmeSBpbnRlcmVzdGluZyAgIApgYGB7cn0KbGFzdF9iYXRjaCA9IGMoMzAwMzEyMzg5LCAzMDQwMTI2OTksIDMwNDAxNzU1MywgMzA0MDIwMjk4LCAzMDQwMjAzNjIsCiAgICAgICAgICAgICAgIDM0MDIyNDgwOCwgMzQwMjMzODk2LCAzNDAyMzk3ODksIDM0MDIzOTc5MCwgMzQwMjM5ODA1KQpnb29kX3NhbXBsZXMgPSBtcF9kZXNbLCAoKCFpcy5uYShtcF9kZXMkUklOKSAmIG1wX2RlcyRSSU4gPj0gNykgJiAKICAgICAgICAgICAgICAgICAgICBtcF9kZXMkU1RBUl9tcWNfZ2VuZXJhbHN0YXRzX3N0YXJfdW5pcXVlbHlfbWFwcGVkX3BlcmNlbnQgPj0gMzAgJgogICAgICAgICAgICAgICAgICAgIG1wX2RlcyRmZWF0dXJlQ291bnRzX21xY19nZW5lcmFsc3RhdHNfZmVhdHVyZWNvdW50c19wZXJjZW50X2Fzc2lnbmVkID49IDMwKSAmCiAgICAgICAgICAgICAgICAgICAgbXBfZGVzJFJOQV9jb25jZW50cmF0aW9uX3BnX3VsID49IDEyNV0KcmVtYWluaW5nX2ludGVyZXN0aW5nID0gc2V0ZGlmZihnb29kX3NhbXBsZXMkc2FtcGxlLCBsYXN0X2JhdGNoKQppbnRlcmVzdGluZ19tZXRhZGF0YSA9IHN1YnNldCh0b3RhbF91bWFwLCBzYW1wbGUgJWluJSByZW1haW5pbmdfaW50ZXJlc3RpbmcpCnRhYmxlKGludGVyZXN0aW5nX21ldGFkYXRhJHBuYV90eXBlKQpnZ3Bsb3QoaW50ZXJlc3RpbmdfbWV0YWRhdGEsIGFlcyh4ID0gcG5hX3R5cGUsIHkgPSBBRXB1cnBsZSkpICsKICBnZW9tX2JveHBsb3QoKQpzZWxlY3Rpb24gPSBpbnRlcmVzdGluZ19tZXRhZGF0YSAlPiUgCiAgZmlsdGVyKHBuYV90eXBlICE9ICJPdGhlciBQbmV1bW9uaWEiIHwgc2FtcGxlID09IDM0MDIzNTExMCkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlLCB0dWJlX2xvY19tYWNyb3BoUk5BX2JveElELCBSTkFfY29uY2VudHJhdGlvbl9wZ191bCkgJT4lIAogIG11dGF0ZShkaWx1dGlvbiA9IGlmZWxzZSgoMjUwIC8gUk5BX2NvbmNlbnRyYXRpb25fcGdfdWwpIDwgMC40LAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSByb3VuZCgxIC8gKDI1MCAvIFJOQV9jb25jZW50cmF0aW9uX3BnX3VsKSAvIDUpICogNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAxKSkgJT4lIAogIG11dGF0ZSh2b2xfZm9yXzI1MF9wZyA9IHJvdW5kKDI1MCAvIFJOQV9jb25jZW50cmF0aW9uX3BnX3VsICogZGlsdXRpb24sIGRpZ2l0cyA9IDIpKQp3cml0ZS5jc3Yoc2VsZWN0aW9uLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzEzX3BpY29fb3B0X2JhdGNoMi5jc3YiKQpzZWxlY3Rpb24KYGBgCiAgIAojIENvbmNsdXNpb25zICAgCiMjIE91dHB1dCBkYXRhIGZvciBwb3N0ZXJpdHkgICAKYGBge3IgZXZhbD1GQUxTRX0KZmluYWxfY291bnRzX3JhdyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBGKQoKI2NsZWFuIG1ldGFkYXRhIGZvciBzYWZlIHNoYXJpbmcKZmluYWxfbWRfc2FmZSA9IGNvbERhdGEobXBfZGVzKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBkcGx5cjo6c2VsZWN0KHNhbXBsZSwgYWdlLCBzZXgsIGRpYWdub3NpcyA9IHBuYV90eXBlLCAKICAgICAgICAgICAgICAgIGRheV9vZl92ZW50aWxhdGlvbiA9IGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwgc3R1ZHlfaWQpCiNjb252ZXJ0IHNjcmlwdCBJRHMgdG8gbmV3IGlkZW50aWZpZXJzCmlkX2NvbnYgPSBkYXRhLmZyYW1lKHNjcmlwdF9pZCA9IHNhbXBsZSh1bmlxdWUoZmluYWxfbWRfc2FmZSRzdHVkeV9pZCkpKSAlPiUgI3NodWZmbGUgSURzIGZpcnN0CiAgbXV0YXRlKGFub255bWl6ZWRfcGF0aWVudF9pZCA9IHNwcmludGYoIiUwNGQiLCAxOm5yb3coaWRfY29udikpKQojYWRkIGJhY2sgdG8gbWQKZmluYWxfbWRfc2FmZSA9IGxlZnRfam9pbihmaW5hbF9tZF9zYWZlLCBpZF9jb252LCBieSA9IGMoInN0dWR5X2lkIiA9ICJzY3JpcHRfaWQiKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLXN0dWR5X2lkKQoKd3JpdGUuY3N2KGZpbmFsX2NvdW50c19yYXcsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy9HRU9fb3V0cHV0LzIwMDcyNF9yYXdfY291bnRzX2dlby5jc3YiKQp3cml0ZS5jc3YoZmluYWxfbWRfc2FmZSwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzL0dFT19vdXRwdXQvMjAwNzI0X2RlaWRlbnRpZmllZF9tZXRhZGF0YV9nZW8uY3N2IikKYGBgCiAgIAojIyBFeHBvcnQgc3VwcGxlbWVudGFsIGZpbGVzICAgCiMjIyBERUEKYGBge3IgZXZhbD1GQUxTRX0KYWxsX2NvbXBhcmlzb25zID0gY29tYm4obGV2ZWxzKG1wX2RlcyREaWFnbm9zaXMpLCAyLCBzaW1wbGlmeSA9IEYpCm5hbWVzKGFsbF9jb21wYXJpc29ucykgPSB2YXBwbHkoYWxsX2NvbXBhcmlzb25zLCBmdW5jdGlvbih4KXsKICByZXR1cm4ocGFzdGUwKHhbMV0sICIgdnMgIiwgeFsyXSkpfSwgImNoYXIiKQpkZWFfaGl0cyA9IGxhcHBseShhbGxfY29tcGFyaXNvbnMsIGZ1bmN0aW9uKHgpewogIGhpdHMgPSBhcy5kYXRhLmZyYW1lKHJlc3VsdHMob2JqZWN0ID0gbXBfZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJEaWFnbm9zaXMiLCB4WzFdLCB4WzJdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gVCkpICU+JSAKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogICAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogICAgYXJyYW5nZShwYWRqKQogIHJldHVybihoaXRzKX0pCm5hbWVzKGRlYV9oaXRzKSA9IG5hbWVzKGFsbF9jb21wYXJpc29ucykKc2F2ZVJEUyhkZWFfaGl0cywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzL0dFT19vdXRwdXQvMjAwNzI4X2J1bGtfZGVhX2NvbXBsZXRlLnJkcyIpCmBgYAogICAKIyMjIEV4cG9ydCBhcyBzaW5nbGUgZXhjZWwgZmlsZSAgIApgYGB7ciBldmFsPUZBTFNFfQpvdXRwdXRfZ2VuZXMgPSBjb3YyX2ttZWFuc19jbHVzdGVyZWQkZ2VuZXMgJT4lIAogIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lX2lkID0gZ2VuZSwgY2x1c3RlciwgZXh0ZXJuYWxfZ2VuZV9uYW1lKSAlPiUgCiAgYXJyYW5nZShjbHVzdGVyKQpuYW1lcyhkZWFfaGl0cykgPSBnc3ViKCJIZWFsdGh5X0NvbnRyb2wiLCAiSEMiLCBuYW1lcyhkZWFfaGl0cykpCm5hbWVzKGRlYV9oaXRzKSA9IGdzdWIoIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIsICJPVlAiLCBuYW1lcyhkZWFfaGl0cykpCm5hbWVzKGRlYV9oaXRzKSA9IGdzdWIoIk90aGVyX1BuZXVtb25pYSIsICJPUCIsIG5hbWVzKGRlYV9oaXRzKSkKbmFtZXMoZGVhX2hpdHMpID0gZ3N1YigiTm9uX1BuZXVtb25pYV9Db250cm9sIiwgIk5QQyIsIG5hbWVzKGRlYV9oaXRzKSkKbmFtZXMoZGVhX2hpdHMpID0gZ3N1YigiQ09WSURfMTkiLCAiQ09WSUQtMTkiLCBuYW1lcyhkZWFfaGl0cykpCmFsbF9zaGVldHMgPSBjKGxpc3QoImstbWVhbnMgZ2VuZXMiID0gb3V0cHV0X2dlbmVzLAogICAgICAgICAgICAgICAgICAgICJrLW1lYW5zIEdPIGVucmljaG1lbnQiID0gY292Ml9rbWVhbnNfY2x1c3RlcmVkJGdvX2RmKSwKICAgICAgICAgICAgICAgZGVhX2hpdHMpCndyaXRlLnhsc3goeCA9IGFsbF9zaGVldHMsIAogICAgICAgICAgIGZpbGUgPSAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzI4X2J1bGtfc3VwcGxtZW50YWxfZGF0YS54bHN4IikKYGBgCiAgIAojIyBBc3NlbWJsZSBmaWd1cmVzICAgCiMjIyBGaWd1cmUgMyAgIApgYGB7cn0KZGVhX2hpdHMgPSByZWFkUkRTKCIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy9HRU9fb3V0cHV0LzIwMDcyOF9idWxrX2RlYV9jb21wbGV0ZS5yZHMiKQpjb3YyX2ttZWFuc19jbHVzdGVyZWQgPSByZWFkUkRTKCIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MjFfa19tZWFuc19jbHVzdGVyZWQucmRzIikKZmlnM19oZWF0bWFwID0gY292Ml9rbWVhbnNfY2x1c3RlcmVkJHBsb3QKZmlnM19oZWF0bWFwX2dnID0gYXMuZ2dwbG90KGZpZzNfaGVhdG1hcCkKdmlyYWxfZXhwcmVzc2lvbl9oZWF0bWFwX2dnID0gYXMuZ2dwbG90KHZpcmFsX2V4cHJlc3Npb25faGVhdG1hcCkKbW9kdWxlX2Nvcl9oZWF0bWFwX3ZlbnRfZ2cgPSBhcy5nZ3Bsb3QobW9kdWxlX2Nvcl9oZWF0bWFwX3ZlbnQpCgpsYXlvdXQgPSAiQUFCQlxuQUFDQ1xuREVGRyIKYnVsa19wbG90X2ZpZzMgPSBmaWczX2hlYXRtYXBfZ2cgKwogIHZpcmFsX2V4cHJlc3Npb25faGVhdG1hcF9nZyArCiAgbW9kdWxlX2Nvcl9oZWF0bWFwX3ZlbnRfZ2cgKwogIG1vZHVsZTE0X3VtYXAgKwogIG1vZHVsZV8xNF9jb3JwbG90ICsKICB0eXBlaV9jb3JwbG90ICsKICB0eXBlaWlfY29ycGxvdCArCiAgICBwbG90X2xheW91dChkZXNpZ24gPSBsYXlvdXQpICsKICAgIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ2EnLCAKICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMjAsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEyMCkpKQoKYnVsa19wbG90X2ZpZzMKYGBgCiAgIAojIyMgRmlndXJlIFMzICAKTWFya2VyIGdlbmVzICAgCmBgYHtyfQpmaWczX2dlbmVzID0gYygiSUw2IiwgIkNDTDI0IiwgIkNDTDgiLCAiQ0NMMiIsICJDQ0w3IiwgCiAgICAgICAgICAgICAgICJSTkFTRTEiLCAiQ0NSMSIsICJNQUZCIiwgIkNTRjJSQSIsICJCQUczIiwgCiAgICAgICAgICAgICAgICJISUYxIiwgIkxBTVAzIiwgIkNDTDIwIiwgIklMMUEiLCAiSUwxQiIsCiAgICAgICAgICAgICAgICJDRDE2NCIsICJNRkdFOCIsICJGQ0dSMkEiLCAiSUwxM1JBMSIsICJGQUJQNCIsCiAgICAgICAgICAgICAgICJNU1IxIiwgIkFYTCIsICJDMVFBIiwgIkFMT1g1IiwgIk1BUkNPIikKZ2VuZV9jb21wcyA9IGxhcHBseShuYW1lcyhkZWFfaGl0cyksIGZ1bmN0aW9uKHgpCnsKICBzdWIgPSBzdWJzZXQoZGVhX2hpdHNbW3hdXSwgZ2VuZV9uYW1lICVpbiUgZmlnM19nZW5lcykgJT4lIAogICAgZHBseXI6OmZpbHRlcihwYWRqIDwgMC4wNSkKICBpZihucm93KHN1YikgPT0gMCkKICB7CiAgICByZXR1cm4oTlVMTCkKICB9CiAgY29tcCA9IHVubGlzdChzdHJzcGxpdCh4LCBzcGxpdCA9ICIgdnMgIikpCiAgc3ViJG51bWVyYXRvciA9IGNvbXBbMV0KICBzdWIkZGVub21pbmF0b3IgPSBjb21wWzJdCiAgcmV0dXJuKHN1YikKfSkKZ2VuZV9jb21wcyA9IGJpbmRfcm93cyhnZW5lX2NvbXBzKSAKCmZpZzNfZ2VuZXMgPSBmaWczX2dlbmVzW2ZpZzNfZ2VuZXMgJWluJSBjKCJJTDYiLCB1bmlxdWUoZ2VuZV9jb21wcyRnZW5lX25hbWUpKV0gI2tlZXAgb25seSBnZW5lcyB3aXRoIHNpZyBkaWZmcyBhbmQgSUw2CmZpZzNfZ2VuZXMgPSBzdWJzZXQoZ2VuZV9jb252LCBnZW5lX25hbWUgJWluJSBmaWczX2dlbmVzKQpzM19jb3VudHMgPSBtY2xhcHBseShmaWczX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwgZnVuY3Rpb24oeCl7CiAgY291bnRzID0gcGxvdENvdW50cyhtcF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICBnZW5lID0geCwKICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gIkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCwKICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgICAgICAgICAgICAgcGMgPSBUKQogIGNvdW50cyRnZW5lID0geAogIHJldHVybihjb3VudHMpfSkKczNfY291bnRzID0gYmluZF9yb3dzKHMzX2NvdW50cykgJT4lIAogIGxlZnRfam9pbiguLCBmaWczX2dlbmVzLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKQoKI2FkZCB5IHBvc2l0aW9ucyBhdXRvbWF0aWNhbGx5CmdlbmVfY29tcHMgPSBtdXRhdGUoZ2VuZV9jb21wcywgbGFiZWwgPSBmb3JtYXQocGFkaiwgZGlnaXRzID0gMiwgc2NpZW50aWZpYyA9IFQpKSAlPiUgCiAgYXJyYW5nZShnZW5lX25hbWUpICU+JSAKICBncm91cF9ieShnZW5lX25hbWUsIC5kcm9wID0gVCkgJT4lIAogIG11dGF0ZSh5ID0gbWF4KGRwbHlyOjpmaWx0ZXIoczNfY291bnRzLCBnZW5lID09IHVuaXF1ZShlbnNlbWJsX2dlbmVfaWQpKSRjb3VudCkgKiAxMCBeICgxICsgMC41ICogYygxOm4oKSkpKSAlPiUgCiAgbXV0YXRlKHlfbG9nMTAgPSAobG9nMTAoeSkgLSAxLjMpKQoKbWFya2VyX2dlbmVfcGxvdCA9IGdncGxvdChzM19jb3VudHMsIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gY291bnQsIGZpbGwgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSkpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSAiSGVhbHRoeVxuQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9ICJOb24tUG5ldW1vbmlhXG5Db250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSAiT3RoZXIgVmlyYWxcblBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9ICJPdGhlclxuUG5ldW1vbmlhIikpICsKICB4bGFiKCIiKSArCiAgeWxhYigiR2VuZSBDb3VudHMiKSArCiAgZmFjZXRfd3JhcCh+Z2VuZV9uYW1lLCBzY2FsZSA9ICJmcmVlX3kiLCBuY29sID0gMykgKwogIGdlb21fc2lnbmlmKGluaGVyaXQuYWVzID0gRiwgCiAgICAgICAgICAgICAgZGF0YSA9IGdlbmVfY29tcHMsCiAgICAgICAgICAgICAgYWVzKHhtaW4gPSBudW1lcmF0b3IsIHhtYXggPSBkZW5vbWluYXRvciwgYW5ub3RhdGlvbnMgPSBsYWJlbCwgeV9wb3NpdGlvbiA9IHlfbG9nMTApLAogICAgICAgICAgICAgIHRpcF9sZW5ndGggPSAwLAogICAgICAgICAgICAgIG1hbnVhbD1UUlVFLAogICAgICAgICAgICAgIGZhbWlseSA9ICJBcmlhbCIsCiAgICAgICAgICAgICAgdGV4dHNpemUgPSA0KSArCnRoZW1lX2J3KGJhc2VfZmFtaWx5ID0gIkFyaWFsIiwgYmFzZV9zaXplID0gMzIpICsKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCiBtYXJrZXJfZ2VuZV9wbG90CmBgYAogICAKYGBge3J9CmNvdjJfa21lYW5zX25vY2x1c3RlcmluZyA9IHJlYWRSRFMoIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9rX21lYW5zX3VuY2x1c3RlcmVkLnJkcyIpCmNvdmVyYWdlX3Bsb3QgPSByZWFkUkRTKCIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA4MDNfY292Ml9jb3ZlcmFnZV9wbG90LnJkcyIpCmZpZ1MzX2hlYXRtYXAgPSBjb3YyX2ttZWFuc19ub2NsdXN0ZXJpbmckcGxvdApmaWdTM19oZWF0bWFwX2dnID0gYXMuZ2dwbG90KGZpZ1MzX2hlYXRtYXApCgpsYXlvdXQgPSAiQUJCXG5BQkJcbkFCQlxuQUJCXG4jQkJcbkNCQlxuREJCIgpidWxrX3Bsb3RfZmlnMyA9IGZpZ1MzX2hlYXRtYXBfZ2cgKwogIG1hcmtlcl9nZW5lX3Bsb3QgKwogIHNhcnNfdGltZV9jb3IgKwogIGNvdmVyYWdlX3Bsb3QgKwogICAgcGxvdF9sYXlvdXQoZGVzaWduID0gbGF5b3V0KSArCiAgICBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdhJykgJiB0aGVtZShwbG90LnRhZyA9IGVsZW1lbnRfdGV4dChzaXplID0gNDgpKQoKYnVsa19wbG90X2ZpZzMKYGBgCiAgIAojIyMgRmlndXJlIFMzICAgCmBgYHtyfQptZCA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShtcF9kZXMpKQpjb2xfdHlwZXMgPSB1bmxpc3QobGFwcGx5KG1kLCBjbGFzcykpCmxpc3RfY29scyA9IG5hbWVzKGNvbF90eXBlc1tjb2xfdHlwZXMgPT0gIkFzSXMiXSkKc2FmZV9tZCA9IG1kICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jKGFsbF9vZihsaXN0X2NvbHMpKSkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQp3cml0ZS5jc3Yoc2FmZV9tZCwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDczMF9idWxrX21wX21ldGFkYXRhLmNzdiIpCmBgYAoK